条款01:视C++为一个语言联邦
- C++是一个多重范式编程语言(multiparadigm programming language),它是一个支持过程形式(procedural)、面向对象形式(object-oriented)、函数形式(functional)、泛型形式(generic)、元编程形式(metaprogramming)的语言。
- 为了理解C++可以从四个方面入手:
- C。区块(blocks)、语句(statements)、预处理器(preprocessor)、内置数据类型(built-in data types)、数组(arrays)、指针(pointers)。
- Object-Oriented C++。classes(构造函数和析构函数),封装(encapsulation)、继承(inheritance)、多态(polymorphism)、virtual函数(动态绑定)。
- Template C++。
- STL。容器(containers)、迭代器(iterators)、算法(algorithms)以及函数对象(function objects)。
条款02:尽量以const,enum,inline替换#define
#define
记号也许在编译器开始处理源码前就被预处理器移走了。于是可能记号没有进入记号表(symbol table)内。- 当我们以常量替换
#define
,如果要在头文件内定义一个常量char*
-based字符串,必须写const两次(顶层const和底层const):const char* const authorName = "Scott Meyers";
但通常用string对象更合宜;如果是class专属常量,为了确保常量至多只有一份,必须称为一个static成员。 - 如果不想别人获得一个pointer或reference指向整数常量,enum可以帮助实现这个约束。
- 用
template<typename T>inline void callWithMax(cons T &a, const T &b);
来代替#define
定义的仿函数,这种template inline函数不仅获得宏带来的效率还有一般函数的所有可预料行为和类型安全性(type safety)。
条款03:尽可能使用const
- const多才多艺,可以在classes外部修饰global或namespace中的常量,或修饰文件、函数、或区块作用域(block scope)中被声明为static的对象。也可以修饰calsses内部的static和non-static成员变量。面对指针,可以指出指针自身、指针所指物,或两者都不是。
- STL迭代器系是以指针塑膜出来,作用跟T*指针一样。声明迭代器为const表示迭代器不指向不同的东西(T *const指针)。但是希望迭代器所指的东西不可改动(模拟const T*指针),需要的是
const_iterator
。 - TextBlock的operator[]可这么使用:
1
2
3
4
5
6
7
8
9
10
11
12class TextBlock {
public:
...
// operator[] for const 对象
const char& operator[](std::size_t position) const
{ return text[position]; }
// operator[] for non-const对象
char& operator[](std::size_t position)
{ return text[position]; }
private:
std::string text;
};注意:non-const operator[]的返回类型是reference to cahr,不是char。因为如果返回类型是个内置类型,那么改动返回值就不合法,即使合法,C++以by value返回对象意味着返回值是副本,而不是本身。1
2
3
4
5
6
7TextBlock tb("Hello");
// 调用non-const TextBlock::operator[]
std::cout << tb[0];
const TextBlock ctb("World");
// 调用const TextBlock::operator[]
std::cout << ctb[0]; mutable
成员变量总是会被更改,即使在const成员函数内。- 当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class TextBlock {
public:
...
const char& operator[](std::size_t position) const
{
...
...
...
return text[position];
}
char& operator[](std::size_t position)
{
// 将op[]返回值的const转除;为*this加上const;调用const op[]
return const_cast<char&>(
static_cast<const TextBlock&>(*this)
[position]
);
}
...
}
条款04:确定对象被使用前已先被初始化
- 永远在使用对象之前将它初始化。对于无任何成员的内置类型,必须手工完成,因为C++不保证初始化它们。
- 构造函数最好使用成员初值列(member initialization list)
- non-local static对象被local static对象替换。以“函数调用”替换“直接访问non-local static对象“。这些reference-returning函数往往十分单纯,这些函数”内涵static对象“的事实使它们在多线程系统中带有不确定性。此时的做法是:在程序的单线程启动阶段(single-threaded startup portion)手工调用所有reference-returning函数,可消除与初始化有关的”</font color=red>竞速形势(race conditions)“。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class FileSYstem { ... };
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
class Directory { ... };
Directory::Directory(params)
{
...
std::size_t disks = tfs().numDisks();
...
}
Directory& tempDir()
{
static Directory td;
return td;
}