视C++为一个语言联邦

  1. C++从最初的C with Classes发展为一个多重泛型编程语言,一个同时支持过程形式、面向对象形式、函数形式、泛型形式、元编程形式的语言。C++可以看做由四个次语言组成:
    (1)C(2)面向对象的C with Classes(3)Template C++(4)STL
  2. 对内置类型而言,传值会比传引用更高效,而用户自定义对象或其他类对象时,由于构造函数和析构函数的存在,传常量引用一般来说都是更好的选择。
  3. C++高效编程守则视状况而变化,取决于你使用C++的哪一部分。

    尽量以const、enum、inline替换#define

  4. 宏定义中使用的名称可能并未进入记号表,因此我们追踪这个名称所发生的错误就会很麻烦,浪费我们的时间。
  5. 使用常量可能比使用#define导致较小量的码,因为预处理器盲目将宏定义名称替换为某个值可能导致目标码出现多份值,若使用常量则不会出现此问题。
  6. 为了确保class专属常量至多只有一份实体,因此必须让它成为一个static成员。因此在类中声明一个static的class专属常量,此时的式子就算是给它赋了初值也是声明式,而非定义式。而且对于类型是整数类型的static class专属常量,只要不对其取地址或者编译器没有特殊要求,我们就可以声明并使用它们无须提供定义式。
    class A{
     private:
     static const int number=5;//声明式
     int scores[number];//使用该常量
    }
    

    由于我们在声明时已获得初值,因此定义时不可以再设初值,并且定义式在类外且一般放进实现文件中。

  7. 在老的编译器上如果不支持static成员在声明式上获得初值,此时可以使用enum hack补偿做法。其理论基础是“一个属于枚举类型的数值可权当ints被使用”,而且enums和defines一样不会导致非必要的内存分配。
  8. 对于形似函数的宏,最好改用inline函数替换#defines,以免发生许多错误的事情。

    尽可能使用const

  9. const修饰指针时,如果关键字const出现在星号左边,表示被指物是常量,如果出现在星号右边,表示指针自身是常量,如果出现在星号两边,表示被指物和指针两者都是常量。
  10. 如果指针被指物是常量,既可以将const写在类型之前,也可以写在类型之后星号之前,这两种写法意义相同。STL中的迭代器是以指针为根据实现出来的,将迭代器声明为const类似于一个T* const指针,表示这个迭代器不得指向不同的东西,但所指东西的值可以改变。如果我们希望迭代器所指的东西不可被改动,类似于const T*,则需要const_iterator。
  11. 令函数返回一个const常量值,可以降低因程序员错误而造成的意外,而又不至于放弃安全性和高效性。将const用于成员函数,是为了确认该成员函数可作用于const对象身上。const成员函数使得class接口容易被理解,得知哪个函数可以改动对象内容而哪个函数不行,另外const成员函数使得“操作const对象”成为可能。
  12. 两个成员函数如果只是常量性不同是可以被重载的。想要在const成员函数内修改变量的值需要在变量类型前加上mutable关键字,mutable关键字可以释放掉non-static成员变量的bitwise constness约束。编译器强制实施bitwise constness,但我们编写程序时应该使用“概念上的常量性”(conceptual constness)。
  13. 当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可以避免重复,但是不能令const版本调用non-const版本,因为const成员函数承诺绝不改变其对象的逻辑状态,但是non-const版本则没有这个承诺。因此这样做会冒很大的风险。

    确定对象被使用前已先被初始化

  14. array(来自C part of C++)不保证其内容被初始化,而STL中的vector却有此保证。因此为了解决这一问题最好的方式就是永远在使用对象前先将它初始化。对于内置类型,我们必须手工完成此事,而内置类型以外的类型,初始化责任落在构造函数上,由其确保每个对象的每一个成员都被初始化。
  15. C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前,在构造函数本体内属于被赋值而不是被初始化。如果成员变量是const或reference,它们就一定需要初值,不能被赋值。
  16. C++有着固定的“成员初始化顺序”,基类早于其派生类被初始化,而class的成员变量总是以其声明顺序被初始化。
  17. 构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。
  18. C++对于“定义于不同的编译单元内的non-local static对象”的初始化相对顺序并无明确定义。
  19. 为免除“跨编译单元之初始化次序”问题,请以local static对象(函数体内的static对象)替换non-static对象(除函数体内的static对象,比如class内static对象、namespace内对象或者全局对象以及file作用域内的static对象)。