Effective C++
-
导读
- 被声明为explicit的构造函数禁止编译器执行隐式类型转换,除非有好理由允许构造函数被用于隐式类型转换,否则把它声明为explicit。
- 拷贝构造操作与拷贝赋值操作。(对象之前是否被定义)
- Pass-by-value与Pass-by-reference。对于用户自定义类型,Pass-by-reference-const往往是比较好的选择。
-
条款01:视C++为一个语言联邦(View C++ as a federation of languages)
- C++并不是一个带有一组守则的一体语言;它是从四个次语言组成的联邦政府,每个次语言有自己的规约。
- C (以C为基础的C++)
- Object-Oriented C++ (C with Classes 面向对象,封装、继承、多态,构造、析构、虚函数等特性)
- Template C++ (泛型编程、模板元)
- STL (标准程序库,分配器、容器、迭代器、算法、适配器、仿函数)
- C++高效编程守则视状况而变化,取决于你用C++的哪一部分。
-
条款02:尽量以const,enum,inline替换#define (Prefer consts,enums,and inlines to #define)
- 以常量替换#define场景一:定义常量指针
const char* const authorName = "Scott Meyers";
string对象通常比其前辈char*-based合宜
const std::string authorName("Scott Meyers");
- 以常量替换#define场景二:定义类专属常量
在类中使用常量申明式
static const int NUM = 5;
或者在类内声明,类外定义const int GamePlayer::NUM = 5;
如果编译器不允许static const int
在类内进行初值的设定,可改用”the enum hack“做法class GamePlayer { private: enum { NUM = 5 }; int scores[NUM]; };
-
enum hack的行为某方面比较像#define而不像const,取一个const的地址是合法的,但取一个enum的地址或#define的地址就不合法,如果不想让别人获得一个pointer或reference指向你的某个整数常量,enum可以帮助实现这个约束。
-
C语言中宏函数一定程度上类似于C++中的模板函数,编写宏函数时为了避免不必要的麻烦,所有实参加上小括号。
-
通过template inline函数来替换宏函数来保证类型安全性。
//以a和b的较大值调用函数f #define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b)) //使用内联函数模板替换 template<typename T> inline coid callWithMax(const T& a, const T& b) { f(a > b ? a : b); }
-
对于单纯常量,最好以const对象或enum替换#define
-
对于形似函数的宏,最好改用inline函数替换#define
-
条款03 尽可能使用const (Use const whenever possible)
- 多才多艺的const,如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在星号两边,表示被指物和指针两者都是常量。
const std::vector<int>::iterator iter
类似于T* const
,迭代器本身就是常量,指向的地址不变
std::vector<int>::const_iterator cIter
类似于const T*
,迭代器指向的内容不
- 在一个函数声明式内,const可以和函数返回值、各参数、函数自身(如果是成员函数)产生关联。
const Rational operator* (const Rational& lhs, const Rational& rhs);
-
将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。这样使class接口比较容易理解,可以得知那个成员函数可以改动对象内容而哪个不行。
-
两个成员函数如果只是常量属性不同,可以被重载。
class 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; }; TextBlock tb("Hello"); std::cout << tb[0]; //调用non-const TextBlock::operator[] const TextBlock ctb("world"); std::cout << ctb[0]; //调用const TextBlock::operator[] //真实程序中const对象大多用于passed by pointer-to-const //或 passed by reference-to-const 传递结果 void print(const TextBlock& ctb) { std::cout << ctb[0]; }
-
注意non-const operator[]返回类型是个reference to char,不是char。如果返回的是char,是以pass by value的形式传值,返回的是一个副本,不是对象本身,如果做出
tb[0] = 'x'
的动作,达不到想要的效果。 -
将某些东西声明为const可以帮助编译器侦测出错误写法。const对象可被施加于任何作用域内的对象、函数参数、函数返回值、成员函数本体。
-
当const 和 non-const 成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。
-
条款04:确定对象被使用前已先被初始化 (Make sure that objects are initialized before they're used)