让自己习惯C++
1.确定对象被使用前已先被初始化
类的构造函数的赋值初始化:
类的构造函数的列表初始化(
更高效):
构造/析构/赋值函数
2.了解C++默默编写并调用哪些函数
如果自己没有声明,编译器就会为类声明一个default 构造函数,copy构造函数,一个copy assignment操作符和一个析构函数。
记住:
- C++不允许让reference指向不同的对象
- C++不允许改变const对象的值
3.若不想使用编译器自动生成的函数,就该明确拒绝
为驳回编译器自动提供的机能,可以将相应的成员函数声明为private,并且不予实现。使用像Uncopyable这样的base class也是一种做法。
class Uncopyable {
protected:
Uncopyable() {} //允许派生类对象构造和析构
~Uncopyable() {}
private:
Uncopyable(const Uncopyable&); //阻止copying
Uncopyable& operator=(const Uncopyable&);
};
class A:private Uncopyable {
...
};
4.为多态基类声明virtual析构函数
- 对于多态基类,如果不声明virtual析构函数,对于指向derived class对象的base class的指针,释放时派生类部分的成员不能释放,会发生内存泄露问题;
- 盲目 为不作为base class的类声明virtual析构函数,会造成类对象大小的膨胀:虚表指针(vptr)的存在;
- 通过声明纯虚析构函数,可以实现virtual析构函数和抽象类的效果,但此时析构函数需要定义;
5.别让异常逃离析构函数
- 析构函数绝对不要吐出异常,如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们或终止程序;
- 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数执行该操作;
6.绝不在构造函数和析构函数中调用virtual函数
生成派生类对象时,首先执行基类的构造函数,基类的构造函数中若调用virtual函数,此时也不会下降到派生类中,因为此时派生类部分还没有被初始化。
派生类将构造的必要信息上传递到基类的例子:
7.在operator=中自我赋值
由于base class的reference或pointer可以指向derived class对象,所以有可能指向同一个对象,从而发生自我赋值。
- operator=的“证同测试”
- 具有异常安全性和自我赋值安全性
- copy-and-swap技术
- by-value传参
8.复制对象时勿忘其每一成分
copying函数应该确保复制对象内所有的成员变量及所有的base class成分
- 显示调用base class的构造函数
- 不要尝试用一个copying函数调用另一个copying函数,应该将公共部分放入第三个函数中进行调用