C++最初的名称C with Classes,一开始只是C加上一些面向对象特性。今天的C++已经是个多重范型编程语言,一个同时支持过程形式(procedual)、面向对象形式(object-oriented)、函数形式(functional),泛型形式(generic),元编程形式(metaprogramming)
本系列为《Effective C++》的读书笔记。本文为第一章让自己习惯C++
- 尽量以const, enum, inline替换#define
|
记号名称ASPECT_RATIO从未被编译器看见,因此编译,调试阶段一旦有出错信息,显示都是1.653而并不是ASPECT_RATIO。解决之道是以一个常量替换上述的宏:
|
|
使用常量可能比使用#define导致较小量的码,因为预处理器“盲目地将宏名称替换为1.653”可能导致目标码出现多份1.653
enum hack:
|
|
对于一些旧式编译器(C++98)不允许“static整数型class常量”完成“in class初值设定”,可用以上方法实现.其理论基础是:一个属于枚举类型的数值可以权当ints被使用。
另外一个常见的#define误用情况是以它实现宏。宏看起来像函数,但不会招致函数调用带来的额外开销。
必须记住宏中的所有实参都需要加上小括号,但即使这样,也有意想不到的情况:
|
|
请记住
- 对于单纯常量,最好以const对象或enum替换#define
- 对于形似函数的宏,最好改用inline函数替换#define
- 尽可能使用const
如果关键字const出现在星号左边,修饰的是*ptr,表示被指物是常量,如果在星号右边,那么修饰的是ptr,即指针自身是常量。
如果被指物是常量,有些程序员习惯将const写在类型前,有些则相反,两种写法意义相同
const最具威力的用法是面对函数声明时的应用。
const成员函数
将const实施于成员函数的目的,是为了确认该成员函数可以作用于const对象身上。这一类成员函数之所以重要,基于两个理由。第一,它们使class接口比较容易被理解。第二,它们使“操作const对象”成为可能。令const成员函数调用non-const函数,就冒了风险:曾经承诺不改动的对象被改动了。因此这是一种错误行为。
请记住
- 将某些东西声明为const可以帮助编译器侦测出错误用法
- 编译器强制实施bitwise constness,但是你编写程序时应该使用“概念上的常量性”
- 当const和non-const成员函数有着实质性等价的实现时,令non-const版本调用const版本可以避免代码重复
- 确定对象被使用前已先被初始化
读取未初始化的值会导致不明确的行为。在某些平台上,仅仅是读取未初始化的值,就可能让你的程序终止运行。请记住,永远在使用对象之前先将它初始化。对于无任何成员的内置类型,必须手动完成此事。例如
|
|
对于内置类型以外的任何其他东西,初始化责任落在构造函数身上。规则很简单:确保每个构造函数都将对象的每一个成员初始化(初始化而非赋值,即通过初始化列表而非构造函数中的赋值操作)。
通过初始化列表其效果和赋值是一样的,但通常效率更高。基于赋值的操作首先调用default构造函数然后在进行赋予新值。而初始化列表的做法避免了这一问题,因为初始值列表中针对各成员变量而设的实参,被拿去作为各成员变量之构造函数的实参。
有些情况下即使面对的成员变量属于内置类型(那么其初始化与赋值的成本相同),也一定得使用初始值列表。例如成员变量是const或references,它们就一定需要初始值,不能被赋值。
C++有着十分固定的“成员初始化次序”。base classes更早与其derived classes,而class的成员变量总是以其声明次序被初始化(即使初始化列表里顺序不同)
针对non-local static对象,C++对于定义于不同的编译单元内的non-local static对象的初始化次序并无明确定义。可以通过一个小小的方法消除这个问题:将每个non-local static对象搬到自己的专属函数内(该对象在此函数内被声明为static)。这些函数返回一个reference指向它所含的对象。然后用户调用这些函数,而不直接访问这些对象。这个手法的基础在于:C++保证函数内的local static对象会在该函数被调用期间,首次遇上该对象之定义式时被初始化。
这么做的好处有两点:
- 保证了所获得的reference将指向一个历经初始化的对象。
- 如果从未调用这个封装函数,就绝对不会引发构造和析构成本。
请记住:
- 为内置类型进行手工初始化,因为C++不保证初始化它们。
- 构造函数最好使用成员初始化列表,而不要在构造函数本体内使用赋值操作。初始化列表中列出的成员变量,其排列次序应该和它们在类中声明的次序相同。
- 为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。