条款01:视C++为一个语言联邦
C++是由下述四个次语言组成:
- C。C++支持面向过程编程,所用基础语法完全等同于C。
- Object-Orited C++。C++面向对象编程,级C with Classed。
- Template C++。C++泛型编程(generic programming)部分。
- STL。STL是C++的一个template程序库,其中包含了大量的容器、迭代器、算法。
因此,C++高效编程守则视状态而变化,取决于使用C++的哪一个次语言。
条款02:尽量以const, enum, inline替换#define
-
#define是预处理器命令,对编译器不可见。因此#define定义的符号,编译器是不可见的,当存在编译报错时,难以排查。使用常量表达式替换宏是一个比较好的做法,如下:
#define ASPECT_RATION 1.653 --> const double AspectRation = 1.653;
-
#define没有作用域的概念,一旦宏被定义,他就在其后的编译过程中有效(除非触发#undef)。
-
使用#define定义的宏来当做函数,由于括号问题容易引入异常。可使用template inline函数替代。如下:
#define CALL_WITH_MA(a, b) f((a) > (b) ? (a) : (b)) // CALL_WITH_MAX(++a, b),a被累加二次,当 a+1 > b时。 --> template<typename T> inline void callWithMax(const T& a, const T&b) { f(a > b ? a :b); }
条款03:尽可能使用const
const允许指定一个语义约束,从而获得编译器的帮助,确保约束不会被违反。
1、const修饰指针
char greeting[] = "hello";
const char *p = greeting; // const出现在\*号左边,表示被指物是常量
char* const p = greeting; // 出现在\*号右边,表示指针自身是常量。
2、const修饰迭代器
std::ventor<int> vec;
const std::vector<int>::iterator iter = vec.begin(); // iter是个常量,不能指向其它迭代器
std::ventor<int>::const_iterator cIter = vec.begin(); // cIter指向的对象时常量,不能被更改
3、const成员函数
const成员函数是指只能读取成员变量,而不能改变成员变量(static除外)。两个成员函数如果只是常量性(constness)不同,可以被重载。
-
bitwise constness(physical constness):不更改对象内任何一个bit
class CTextBlock { public: ... char & operator[] (std::size_t position) const { // bitwise声明,但其实不适当,原因是返回值可以被修改。 return pText[position]; } private: char *pText; };
-
logical constness:const成员函数可以修改对象内某些成员变量,但客户端侦测不出来。
使用 mutable 关键字修饰的成员变量,表示总能可以被更改,即使在const成员函数内。
-
在const和non-const成员函数中避免重复
考虑到两个成员函数的功能几乎一样,唯一不同在于一个返回const,另一个返回non const,所以实现两个这样的函数,容易造成代码重复。
一种可用的方法是,将重复代码放到一个新的函数调用,但这种方式还是存在问题:函数调用、两次return等。另一种方式是另其中一个调用另一个。class TextBlock { public: const char& operator[] (std::size_t position) const { ... ... ... return text[position]; } char& operator[] (std::size_t position) { return const_cast<char&>( static_cast<const TextBlock&>(*this)[position]); } ... };
条款04:确定对象被使用前已被初始化
C++规定,对象的成员变量初始化动作发生在进入构造函数本体之前,所以对于构造函数,最好实现成员初始化列表。值得注意的是,class的成员变量总是以其声明次序被初始化。