条款一:将C++视为一个语言联邦(将C++划分为不同的次级语言)
将C++视为四个次语言,进入不同的次语言领域有不同的标准:
- C:内置数据类型,预处理,数组,指针
- Object-Oriented C++:类,封装,继承,多态,虚函数
- Template C++:模板元编程
- STL:STL组件
条款二:尽量以const,enums, inline 替换#define
使用const或者enums替换#define,使用template的inline函数代替宏(#define)
- 用const替换#define定义的宏便于调试,可以再符号表里找到定义的常量
- 定义常量指针要用两个const: const char* const authorName = “Scott Meyers”;(这里说常用string定义authorName如:const std::string authorName = “Scott Meyers”)
- 定义class的专属常量时,要写成static,确保该常量只有一个实体
- enumhack,用一个enum代替int常量,可以防止别人获得指向该常量的指针
用inline代替define:
1
2
3
4
5
6
7
template<typename T>
inline void callWithMax(const T& a, T& b)
{
f(a > b ? a : b);
}相对于宏,这种写法不容易出错。
条款三:尽可能使用const
要尽可能使用const,对于需要约束的变量一定要进行约束。
1 | char* const p = str; //指针是常量,指针指向数据不是 |
若被指物是常量,const在星号前,指针自身是常量,const在星号后。
对于迭代器,const vector<int>::iterator iter = vec.begin()
作用类似于T * const
而vector<int>::const_iterator iter = vec.begin()
作用类似于const T*
bitwise constness:成员函数在不更改对象的任何成员变量时才能称为const
1 | //不具备const性质但可以通过bitwise constness检查的例子: |
logical constness:在客户端看来是const的,也就是说实现上可能会改变数据成员的值,但是用户却感觉不到(mutable关键字)。
1 | class CTextBlock{ |
const成员函数:
对于实现相同功能的成员函数,对他们的const 和非const版本,用非const版本调用const版本避免代码重复。
条款四:确定对象使用前已经被初始化
- 对于内置类型,必须在使用之前进行初始化
- 当使用构造函数时,使用初始化列表来定义构造函数。
- 对于静态对象,当多个non-local static对象处于不同的源文件内,且有初始化顺序的约束,即在使用一个对象时必须保证另一个对象已经被初始化,这时要使用单例模式。
条款五:了解C++会默认调用的函数
C++会自动提供默认的构造函数,拷贝构造函数,析构函数,和赋值运算符,且均为public inline 。
1 | //如果你写了一个空类 |
对于拷贝构造函数和赋值运算符,默认的版本只单纯将来源对象的每一个non-static成员拷贝到目标对象,注意,若对成员的拷贝操作不合法时,例如当成员是引用类型的时候(引用类型不能进行拷贝),编译器会报错,此时调用默认的拷贝构造函数和赋值运算符是很危险的。
当基类将赋值运算符设为private,其子类就不会提供默认的拷贝运算符(原因是基类无法拷贝)。
- 使用自定义类型时要注意是否使用编译器提供的默认构造函数,析构函数,拷贝构造函数,赋值运算符。