对话#19:新的起点,第一部分

发表于:2007-07-01来源:作者:点击数: 标签:
[声明]:本英文资料源自于Herb Sutter 创建的“Conversation”栏目,“C++ 翻译小组”的翻译作品供学习交流与参考用途,不得用于任何商业用途。未经Herb Sutter、Jim Hyslop同意,不得转载;对于违反以上条款,翻译小组对此不负任何责任;特此声明。 文章来源
[声明]:本英文资料源自于Herb Sutter 创建的“Conversation”栏目,“C++ 翻译小组”的翻译作品供学习交流与参考用途,不得用于任何商业用途。未经Herb Sutter、Jim Hyslop同意,不得转载;对于违反以上条款,翻译小组对此不负任何责任;特此声明。

文章来源:http://www.gotw.ca
版权归属:Herb Sutter and Jim Hyslop
译    者:徐波

对话#19:新的起点,第一部分 

    舞厅里异常安静。

    我们完全没料到会发生这种情况。不管怎样,对于怎么离开这地方,我们一点头绪都没有。现在已经是进攻部队侵入我们在木卫二冰层下的外星城内据点的第二天了,而我们在地面上的部队却是鞭长莫及,无法给予我们帮助。吉尔伯下令撤入舞厅,并在门口设置障碍。房间很大,但幸运的是它的入口很少。一些队友离开了我们,乘着撤退时秩序混乱干脆投降了。我和珍妮就没这个机会,我们被吉尔伯和他的官员们看得紧紧的。

    舞厅里很冷,而且越来越冷。吉尔伯同意打开两只便携式取暖器,因为我们所带的电池一年也用不完。温度明显回升了。

    我们同时带上了几个外星文物,插上了电,但仍显得很神秘,我们刚刚才把它们激活,根本没有时间进行实验。雅格跟我们在一起,他可是个重要人物,他比其他人更懂这个神秘古城的文字。

    这三个十英尺直径的金属球仍挂在半空中,每个仍展示不同的图象:微黄的草地,附近有些象树一样的东西;黄昏时刻的沙滩;象这个房间一样的金属屋,有很多柜子,我们曾看到的那个瞪着我们的灰袍人现在已经跑掉了。他没再回来,也没其它人出现。我们知道把小东西扔进球里也就是把它们添加到图象中;我们开始想到金属球会不会是“大门”,便把一节用过的电池扔向草地,它碰了碰树状物,在草地蹦了几下,然后就不动了。电池仍在我们的视野之中,没有什么东西朝它扑去,它自己也没什么反应。

    我把头转向珍妮,我们谈论其它一些寒冷而又安静的时刻,这有助于分散我们的注意力。此时,雅格在房间的另一端继续仔细地对其中一种文物进行实验,希望能起一点作用。

- - - - - - - - - - - - - - - - - - - - - - - - -

    办公室内非常安静。

    这并没有出乎意料。不管怎样,今天是二月二日,许多人都去渡假了。我正在折腾一些小型的程序代码,这也是我计划好的,因为我现时的状态不适合搞大型的程序。

    我刚刚接到一些有关“内部库”的开发要求,虽然并不是什么了不起的大项目,但我还是颇感兴奋。你知道,我们的公司并没有单独成立正式的小组来开发供整个公司使用的基础软件库。虽然我认为这种库很有意义,但对这种组织风格并不感冒,相信Guru也是如此。不过,我们已经拥有一些基于一般东西的内部库,由一些工程所共享。这些内部库并没有单独的“主人”,但项目的增加和修改由其中一位经验丰富的开发人员进行审查。如果我们写了一些可供重用的候选内容,就将其提交给共享库。偶尔,有人会请求增加某种特性,通常该特性在共享区尚未提供,但可能是内部库应该具备的。如果有谁自信有这个能耐,就接受这个请求,写出解决方案

    所以,当我被冠之为“可能有这个能耐”,受邀为内部库写一个扩展的东西时,自然是颇感兴奋。我感到兴奋的另一个原因是他们从没请鲍勃来干。这让我有了一点骄傲的资本。唉!年轻人的虚荣啊。

    问题看上去很简单:“写一个ConvertBase函数,它接受一个表示基数为N的数字的string,将其转换为另一个string,代表的是相同的数字,可基数换成了M。”

    我的第一感觉是写一个硬编码的解决方案,就象下面这样:

string ConvertBase( size_t base1, size_t base2,
const string& src )
{
    long value = 0;

    // 从src中读入基数base1。
    for( int i = 0; i < src.size(); ++i )
    {
        // if src[i]是一个有效的base1字符,
        // 将值乘以base1,然后加上下一个数字;
        // else if src[i]是空格break;
        // else 抛出一个逻辑错误;
    }

    // 将基数base2数值写到dest
    string dest;
    while( value > 0 )
    {
        // 找到最高位的base2数字,
        // 添加到dest,
        // 适当地减小数值。
    }
}
    正当我埋头琢磨,尚未写完最后一行注释时,耳后传来一声温和的清嗓子的声音,我意识到Guru来了。

    我神情严峻,周围一片沉寂。

    接着我听到沙沙的翻书声,不用回头我就知道,Guru把笔搁在书中,又合上了书。然后是她平静而又低沉的声音:“傍晚好,我的孩子。”

    “啊,傍晚好,老师,”我回答道。如果她摆出了那副滑稽的架子,那鲍勃肯定在附近,这副模样对于成功地吓唬鲍勃是非常重要的。

    “你的代码,”她摆着手势,围着我踱着步,审视着显示器,并用笔在其上比划着,“跟247号请求惊人地相似。”

    “哦,是的,就是它,”我承认,“这正是我的工作内容。看上去可能会搞得比较长。”

    她若有所思地点点头,并不吭声。过了一会,她补充道:“你是否注意过314号请求。”

“哦,嗯……没有。”我老实承认。

    “这没什么,314号请求要求一种从文本流中读写一个任意基数的数字的方法。我想编写314号请求代码的人最终跟你现在所写的会差不多。我能提个建议吗,徒弟?”

    “真的,你希望我顺便把314号请求也完成了?”我问道,希望在我心中升起。如果说受邀写一个共享库方法是一种荣耀的话,想想在这么短的时间内连续受邀编写两个又是何等风光啊!

    “是的,但并不是马上,”Guru说道,理了理耳后一络灰白的头发。“编程有一个原则:我们经常能够在我们的代码中通过首先编写测试例来获得有益的见识。贝克、福勒、马丁和另一些人将这个信条传播给任何会聆听的人,也传播给许多不想理会的人。在这个例子里,假如你已经有了一些跟314号请求有关的代码,为什么不为247号请求写些代码呢,为247号请求写一个简单的测试例,可以从314号请求的主干代码中做些修改,能让测试例通过编译。最后,你从247号请求的代码中归纳出314号请求的解决方案应该采用的形式,确认这种形式可以被提出314号请求的人所接受,然后就是具体的编码了。”

    我眨了眨眼,“我想我明白你的意思了。我首先在247号请求中提出使用了314号请求中尚未完成的那部分方法,这样我就可以看一下314号请求的方法应该是怎样的,对不对?”

  “对!”

    “OK,”我略作沉吟,接着在键盘上忙碌起来。我可以假定我已经有一个“能够从一个文本流中读写任意基数的数值的方法”。对,我如果有了这玩意,我可以使用流在各个基数之间相互翻译。深思熟虑之后,我最终敲定如下代码:

string ConvertBase( size_t base1, size_t base2,
const string& src )
{
stringstream s1( src );
long value;

if( !( s1 >> Num( base1, value ) ) || 
!( s1 >> std::ws ).eof() )
throw logic_error
( "src is not a valid number" );

stringstream s2;
if( !( s2 << Num( base2, value ) ) )
throw logic_error
( "unexpected error emitting converted number" );

return s2.str();
}
   接着我又写了一个简单的测试例,简单地提供足够的Num桩模块,使这个例子能通过编译:

class Num
{
public:
Num( size_t base, long& value ) :
base_(base), value_(value) { }

size_t Base() const { return base_; }
long& Value() { return value_; }

private:
size_t base_;
long& value_;
};

istream& operator>>( istream& i, Num& n )
{
string s;
i >> s;
// todo: really convert input to n´s base_
// todo: 真正将输入转换为基数为n的数值。
n.value_ = 255; 
return o;
}

ostream& operator<<( ostream& o, const Num& /* n */ )
{
// todo: really output n.value_ in n.base_
// todo: 真正以n.base为基数将n.value输出
return o << "FF"; 
}

int main()
{
string result = ConvertBase( 10, 16, "255" );
cout << result << endl;
return result == "FF" ? 0 : 1;
}
    编译器只抓到几个打字错误,改正之后,我心满意足地看到这办法确实管用。接下来,我知道必须为314号请求弄出完整的方案,也就是真正实现Num中的<<和>>操作。

    我看了看表,下班时间早过了,但还能赶上车,不会误了跟安娜的约会。314号请求嘛,明天再说喽。

- - - - - - - - - - - - - - - - - - - - - - - - -

    我看了看表,早就过了该我们去睡的时间,我们还紧去睡。门的另一边不时传来敲击声,大概是入侵部队在砸门,但目前还没有更多的动作。这些奇怪的球或大门可以挨到早晨,除非有进一步的情况发生。虽然吉尔伯的手下仍在尝试使用我们的便携式通讯仪,试图与地面上取得联系,或者与我不知道的过往船只联系,但我有一种感觉,大门是我们唯一的出路。

[关于作者]

Herb Sutter

是个独立顾问,也是ISO/ANSI C++标准委员会的秘书。你可通过hsutter@acm.org.联系他

Jim Hyslop

Leitch Technology International Inc.资深的软件设计师,你可通过jim.hyslop@leitch.com联系他


原文转自:http://www.ltesting.net