条款

  1. 将C++视为一个语言联邦。今天C++已经成为一个多重泛型编程语言。一个同时支持过程形式、面向对象形式、函数形式、泛型形式、元编程形式的语言。
    在C++98标准中:C++分为C、C with class、template、STL四部分组成。
  2. 尽量用const、enum、inline替换#define(尽量使用编译器替换预处理器)。
    常量定义式通常放在头文件中。
    #define不重视作用域。
  3. 尽可能使用const (use const whenever possible)
    将某些东西声明为const可帮助编译器侦测出错误用法,const可被施加在任何作用域的对象、函数参数、函数返回类型和成员函数本体。
    编译器强制实施bitwish constness,但是你编写程序时应该使用概念上的常量性(conceptual constness)
    当const函数和non-const函数有实质等价的实现时,令non-const版本调用const可避免代码重复。
  4. 确定对象使用前已经先被初始化。
    对内置型对象进行手工初始化,因为C++不保证初始化它们。
    构造函数最好使用member initialization list,而不要在构造函数本体内使用赋值操作。list列出的成员列表的排列顺序应该和声明顺序相同。
    为了免除“跨编译单元之初始化次序的问题,请以local static对象替换non-local static对象。
  5. Know what functions C++ silently write and calls
    编译器可以暗自为class创建default构造函数,copy构造函数,copy assignment操作符以及析构函数。
  6. Explicitly disallow the use of compiler-generated functions you do not want.

  7. Declare destructors virtual in polymorphic base class.
    polymorphic(带有多态性质的)base classes 应该声明一个virtual析构函数,如果class拥有一个virtual函数,那么它应该拥有一个virtual析构函数。
    classes的设计目的如果不是用来作为base classes使用,或者不是为了具备ploymorphically(多态性),就不应该声明virtual析构函数。

  8. Prevent exceptions from leaving destructors.不要让异常逃离析构函数
    析构函数绝对不要吐出异常,如果一个被析构函数调用的函数有可能会抛出异常,析构函数应该捕捉任何异常并吞下他们(不传播)或结束程序。如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。

  9. Never call virtual functions during on construction or destruction.绝对不在构造和析构过程中调用virtual函数。
    在base class构造期间,virtual 函数并非是virtual函数。
  10. Have assignment operators return a references to *this. 令赋值操作符返回一个references to *this 赋值采用的是右结合律。
  11. Handle assignment to self in operator= 在赋值操作符中处理自我赋值
    确保当对象自我赋值时operator=仍然有良好的行为。其中技术包括比较“来源对象”和“目的对象”的地址,精心周到的语句顺序、以及copy-and-swap。
    确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象的时候,其行为仍然正确。
  12. Copy all part of an object.复制对象时勿忘记其中的每一个成分。
    copying 函数应该确保复制了对象中的所有的成员变量以及所有的base class成分。
    不要尝试用某一个copying函数实现另一个copying函数,例如copy构造函数和copy操作符,应该将共同代码放到第三个函数中,并由两个copy函数共同调用。
  13. Use objects to manage resources
    获得资源之后立刻放到管理对象中。
    管理对象运用析构函数确保资源被释放。
    资源取得时机便是初始化时机。
  14. Think carefully about copying behavior in resource-managing classes.
  15. Provide access to raw resources in resource-managing classes.在资源管理类中提供对原始资源的访问。
    对原始资源的访问可能经由显式转换或隐式转换,一般来讲,显式转换比较安全,隐式转换令客户感觉方便。
  16. Use the same form in corresponding use of new and delete .成对使用new和delete时使用相同形式。
    最好尽量不要对数组形式做typedefs动作。
  17. 使用独立语句将new出来的对象放入智能指针中。
    编译器对“跨越语句的各项操作”没有重新排列的自由(只有在语句内才会有此自由度)。
  18. 让接口容易被使用,不容易被误用。
    促进接口正确使用的方法包括接口的一致性,以及与内置类型的行为兼容。
    阻止误用的方法包括建立新的类型,限制类型上的操作,束缚对象值,以及消除客户的资源管理责任。
  19. Treat class design as type design 设计class犹如设计type
    设计class时需要涉及的问题:
    • 新type的对象应该如何被创建和销毁。
    • 对象的初始化和对象的赋值有什么差别。
    • 新type的对象如果被pass by value,意味着什么。
    • 什么是新type的”合法值“。
    • 你的新type是否需要配合某个继承图系(inheritance graph)。
    • 你的新type需要哪些转换。
    • 什么样的操作符和函数对于此type是合理的。
    • 什么样的函数应该设置为private。
    • 谁该取用新type的成员。
    • 什么是新type的“未声明接口”。
    • 你的新type有多么一般化。
    • 你真的需要一个新type吗?
  20. Prefer pass-by-reference-to-const to pass-by-value
    此规则不适用与stl的迭代器和函数对象
  21. Don‘t want to try return a reference when you must return an object.
  22. Declare data members private.
    protected并不比public更具有封装性。
  23. Prefer non-member non-friend functions to member functions
    这样可以增加封装性,包裹弹性(packaging flexibility)和机能扩充性。
  24. 若所有参数都需要类型转换,请为此采用non-member函数
  25. Consider support for a non-throwing swap考虑写出一个不抛异常的swap函数。
    当std::swap对你的类型的转换效率不高的时候,提供一个swap成员函数,并确定这个函数不抛异常。
    如果你提供一个member swap, 也应该提供一个non-member swap 来调用前者,对于class(而非templates),也请特化std::swap.
    千万不要尝试在std内加入某些对于std而言全新的东西。
  26. Postpone variable definitions as long as possible.尽可能的推迟变量定义的位置。
    单一对象可能会有一个以上的地址(如base×指向它的地址和derived×指向它的地址。
  • 技巧:
    • 所谓软件设计,是“令软件做出你希望它做的事情”的步骤和做法。
    • 在C++编译器的底层会发现,reference往往以指针实现出来。因此,pass by reference通常意味这传递的是指针。
    • 对于内置类型来说 pass by value 往往比pass by reference 效率高一些。
文章目录
,