条款 01:视 C++ 为一个语言联邦
- C++ 并不是 C 的超集,双方都有自己独特的地方。
- C++ 语言由四个次语言组成,每一个部分有自己独立的高效编程守则,要清楚自己运用的是哪一部分:
- C:C++ 以 C 为基础;
- Object-Oriented C++:也就是 C with classes 所诉求的;
- Template C++:C++ 的泛型编程部分;
- STL:template 程序库。
条款 02:尽量以 const、enum、inline 替换 #define
- 尽量以编译器代替预处理器。
- 在 C 语言中,我们一般使用宏定义 #define 语句来声明某些常量或是函数,但是 C++ 中推荐使用 const、enum、inline 等来替代 #define 的使用。
- #define 语句在使用中有诸多不足,从原理上讲,在程序编译的预处理阶段,编译器会把 #define 声明的代码直接插入程序中。【注意这里说的直接插入:那意味着如果不加括号,一些函数操作可能会出错】
- #define 是预处理器处理的部分,当编译出错时,不容易发现错误发生在哪里,其次由于预处理器盲目的替换,会导致目标码的增大。
- 对于常量,用 const 或者 enum 替换 #define:
- const 的写法要优于 #define;
const std::string
的写法要优于const char* const
。 - #define 并不重视作用域,所以无法定义 class 中专属常量变量。
- class 专属常量的获得:需要将成员声明为 static(即使给予数值,在类内仍然是声明),然后再在类外定义(如果类内已经赋值,在类外不需要再给)。
- 但有时编译器不允许前面的类内初值设定,可以利用 enum hack 代替 static const。
- enum 的使用更像是 #define 而不像 const,既无法获得 #define 的地址,也无法让别人获得一个 pointer 或 reference 指向 enum(因为 enum 的地址不合法)。
- const 的写法要优于 #define;
- 对于形似函数的宏,改用 inline 函数替换 #define。
- #define 的实现宏有时会带来额外的开销。
条款 03:尽可能使用 const
- const 能修饰的东西特别多。
- const 与指针的结合特别直观,与 STL 迭代器的结合也是一样。
- const 在函数声明中更为方便,可以和返回值、参数、函数自身产生关联。
- const 的习惯使用可以降低因用户错误而造成的意外。
- 举个例子:加了 const,能避免想要键入 == 却意外键入 = 的错误。
- 编译器强制实施 bitwise constness,但程序员编写程序时应该使用概念上的常量性(conceptual constness)。
- const 修饰成员函数时,代表该函数内不允许修改成员函数的任何属性(即使某些属性并没有被声明为 const)。【bitwise constness】
- mutable 关键字可以破除这个限制,即是允许程序员适当地使用 mutable 关键字来让 const 成员函数可以改变某些值。【logical constness】
- 常量性(constness)也可以是重载的原因。
- const 成员函数的作用:使接口容易被理解、消除误操作的隐患、使操作 const 对象成为可能。
- 最后一个作用的意思是指,当我们创建了一个 const 对象,只能调用 const 对象的 const 成员函数。
- 当 const 和 non-const 成员函数有着实质等价的实现时,令 non-const 版本调用 const 版本可避免代码重复。
条款 04:确定一个对象被使用前已经先被初始化了
- 为内置型对象进行手工初始化,因为 C++ 不保证初始化它们。
- 对于 C++ 的对象而言,其初始化的任务落在了构造函数(constructor)上。
- 初始化不等于赋值:
// 初始化后赋值(复制行为): GamePlayer::GamePlayer(char *pText, size_t slength, bool valid) { this->pText = pText; this->slength = slength; this->valid = valid; } // 初始化: GamePlayer::GamePlayer(char *pText, size_t slength, bool valid) : pText(pText), slength(slength), valid(valid) { //do nothing }
- 要记得总是在初值列中列出所有成员变量。
- C++ 有十分固定的成员初始化顺序(父类先于子类,类的内部以成员声明次序初始化)。
- 初始化不等于赋值:
- 为了免除跨编译单元的初始化次序问题,用本地的 static 对象来替代非本地(non-local)的 static 对象。