|            
Bjarne Stroustrup的FAQ:C++的风格与技巧 
    翻译:左轻侯 
    http://www.wushuang.net/article/bsfaq.htm 
    (译注:本文的翻译相当艰苦。Bjarne Stroustrup不愧是创立C++语言的一代大师,不但思想博大精深,而且在遣词造句上,也非常精微深奥。有很多地方,译者反复斟酌,都不能取得理想的效果,只能尽力而为。 
    Html格式的文档见译者主页:http://www.wushuang.net 
    如果你对这个翻译稿有任何意见和建议,请发信给译者:onekey@163.com。 
    原文的地址为:http://www.research.att.com/~bs/bs_faq2.html) 
    (Bjarne Stroustrup博士,1950年出生于丹麦,先后毕业于丹麦阿鲁斯大学和英国剑挢大学,AT&T大规模程序设计研究部门负责人,AT&T 贝尔实验室和ACM成员。1979年,B. S开始开发一种语言,当时称为"C with Class",后来演化为C++。1998年,ANSI/ISO C++标准建立,同年,B. S推出其经典著作The C++ Programming Language的第三版。) 
    这是一些人们经常向我问起的有关C++的风格与技巧的问题。如果你能提出更好的问题,或者对这些答案有所建议,请务必发Email给我(bs@research.att.com)。请记住,我不能把全部的时间都花在更新我的主页上面。 
    更多的问题请参见我的general FAQ。 
    关于术语和概念,请参见我的C++术语表(C++ glossary.)。 
    请注意,这仅仅是一个常见问题与解答的列表。它不能代替一本优秀教科书中那些经过精心挑选的范例与解释。它也不能象一本参考手册或语言标准那样,提供详细和准确的说明。有关C++的设计的问题,请参见《C++语言的设计和演变》(The Design and Evolution of C++)。关于C++语言与标准库的使用,请参见《C++程序设计语言》(The C++ Programming Language)。 
    目录: 
    我如何写这个非常简单的程序? 
    为什么编译要花这么长的时间? 
    为什么一个空类的大小不为0? 
    我必须在类声明处赋予数据吗? 
    为什么成员函数默认不是virtual的? 
    为什么析构函数默认不是virtual的? 
    为什么不能有虚拟构造函数? 
    为什么重载在继承类中不工作? 
    我能够在构造函数中调用一个虚拟函数吗? 
    有没有“指定位置删除”(placement delete)? 
    我能防止别人继承我自己的类吗? 
    为什么不能为模板参数定义约束(constraints)? 
    既然已经有了优秀的qsort()函数,为什么还需要一个sort()? 
    什么是函数对象(function object)? 
    我应该如何对付内存泄漏? 
    我为什么在捕获一个异常之后就不能继续? 
    为什么C++中没有相当于realloc()的函数? 
    如何使用异常? 
    怎样从输入中读取一个字符串? 
    为什么C++不提供“finally”的构造? 
    什么是自动指针(auto_ptr),为什么没有自动数组(auto_array)? 
    可以混合使用C风格与C++风格的内存分派与重新分配吗? 
    我为什么必须使用一个造型来转换*void? 
    我如何定义一个类内部(in-class)的常量? 
    为什么delete不会将操作数置0? 
    我能够写“void main()”吗? 
    为什么我不能重载点符号,::,sizeof,等等? 
    怎样将一个整型值转换为一个字符串? 
    “int* p”正确还是“int *p”正确? 
    对于我的代码,哪一种布局风格(layout style)是最好的? 
    我应该将“const”放在类型之前还是之后? 
    使用宏有什么问题? 
    我如何写这个非常简单的程序? 
    特别是在一个学期的开始,我常常收到许多关于编写一个非常简单的程序的询问。这个问题有一个很具代表性的解决方法,那就是(在你的程序中)读入几个数字,对它们做一些处理,再把结果输出。下面是一个这样做的例子: 
    #include 
    #include 
    #include 
    using namespace std; 
    int main() 
    { 
    vector v; 
    double d; 
    while(cin>>d) v.push_back(d); // 读入元素 
    if (!cin.eof()) { // 检查输入是否出错 
    cerr < "format="" error\n";="">
    return 1; // 返回一个错误 
    } 
 
    cout < "read="" "="">< v.size()="">< "="" elements\n";="">
    reverse(v.begin(),v.end()); 
    cout < "elements="" in="" reverse="" order:\n";="">
    for (int i = 0; i 
    return 0; // 成功返回 
    } 
 
 
    对这段程序的观察: 
    这是一段标准的ISO C++程序,使用了标准库(standard library)。标准库工具在命名空间std中声明,封装在没有.h后缀的头文件中。 
    如果你要在Windows下编译它,你需要将它编译成一个“控制台程序”(console application)。记得将源文件加上.cpp后缀,否则编译器可能会以为它是一段C代码而不是C++。 
    是的,main()函数返回一个int值。 
    读到一个标准的向量(vector)中,可以避免在随意确定大小的缓冲中溢出的错误。读到一个数组(array)中,而不产生“简单错误”(silly error),这已经超出了一个新手的能力——如果你做到了,那你已经不是一个新手了。如果你对此表示怀疑,我建议你阅读我的文章“将标准C++作为一种新的语言来学习”("Learning Standard C++ as a New Language"),你可以在本人著作列表(my publications list)中下载到它。 
    !cin.eof()是对流的格式的检查。事实上,它检查循环是否终结于发现一个end-of-file(如果不是这样,那么意味着输入没有按照给定的格式)。更多的说明,请参见你的C++教科书中的“流状态”(stream state)部分。 
    vector知道它自己的大小,因此我不需要计算元素的数量。 
    这段程序没有包含显式的内存管理。Vector维护一个内存中的栈,以存放它的元素。当一个vector需要更多的内存时,它会分配一些;当它不再生存时,它会释放内存。于是,使用者不需要再关心vector中元素的内存分配和释放问题。 
    程序在遇到输入一个“end-of-file”时结束。如果你在UNIX平台下运行它,“end-of-file”等于键盘上的Ctrl+D。如果你在Windows平台下,那么由于一个BUG它无法辨别“end-of-file”字符,你可能倾向于使用下面这个稍稍复杂些的版本,它使用一个词“end”来表示输入已经结束。 
    #include 
    #include 
    #include 
    #include 
    using namespace std; 
    int main() 
    { 
    vector v; 
    double d; 
    while(cin>>d) v.push_back(d); // 读入一个元素 
    if (!cin.eof()) { // 检查输入是否失败 
    cin.clear(); // 清除错误状态 
    string s; 
    cin >> s; // 查找结束字符 
    if (s != "end") { 
    cerr < "format="" error\n";="">
    return 1; // 返回错误 
    } 
    } 
    cout < "read="" "="">< v.size()="">< "="" elements\n";="">
    reverse(v.begin(),v.end()); 
    cout < "elements="" in="" reverse="" order:\n";="">
    for (int i = 0; i 
    return 0; // 成功返回 
    } 
    更多的关于使用标准库将事情简化的例子,请参见《C++程序设计语言》中的“漫游标准库”("Tour of the Standard Library")一章。 
    为什么编译要花这么长的时间? 
    你的编译器可能有问题。也许它太老了,也许你安装它的时候出了错,也许你用的计算机已经是个古董。在诸如此类的问题上,我无法帮助你。 
    但是,这也是很可能的:你要编译的程序设计得非常糟糕,以至于编译器不得不检查数以百计的头文件和数万行代码。理论上来说,这是可以避免的。如果这是你购买的库的设计问题,你对它无计可施(除了换一个更好的库),但你可以将你自己的代码组织得更好一些,以求得将修改代码后的重新编译工作降到最少。这样的设计会更好,更有可维护性,因为它们展示了更好的概念上的分离。 
    看看这个典型的面向对象的程序例子: 
    class Shape { 
    public: // 使用Shapes的用户的接口 
    virtual void draw() const; 
    virtual void rotate(int degrees); 
    // ... 
    protected: // common data (for implementers of Shapes) 
    Point center; 
    Color col; 
    // ... 
    }; 
 
 
    class Circle : public Shape { 
    public: 
    void draw() const; 
    void rotate(int) { } 
    // ... 
    protected: 
    int radius; 
    // ... 
    }; 
 
 
    class Triangle : public Shape { 
    public: 
    void draw() const; 
    void rotate(int); 
    // ... 
    protected: 
    Point a, b, c; 
    // ... 
    }; 
 
    设计思想是,用户通过Shape的public接口来操纵它们,而派生类(例如Circle和Triangle)的实现部分则共享由protected成员表现的那部分实现(implementation)。       [1] [2] [3] [4]  下一页  
 |