Effective C++(二)构造、析构和赋值操作

来源:互联网 发布:淘宝店受限怎么解决 编辑:程序博客网 时间:2024/05/20 01:35

条款5 :了解C++默认生成并调用哪些函数。

1)编译器在编译器需要的情况下会自动为class创建default构造函数、copy构造函数、copy assignment操作符以及析构函数,自动生成的函数为public而且inline。(注意:不是任何class没有定义这些函数,编译器都会自动生成)。

2)编译器生成的这些函数只满足编译器的需要而不是程序的需要。


条款6 :若不想使用编译器自动生成的函数,就应该明确拒绝。

1)拒绝编译器自动(暗自)提供的功能的方法:

*将相应成员函数声明为private并且不予实现。客户使用时编译阶段报错;member或友元类使用时链接阶段出错。例如:将copy构造函数放在private且不实现,则会拒绝对象的复制操作。

*使class继承一个base class,这个基类将相应的函数声明为private且不实现,这样使用class相应操作时都会在编译阶段报错。


条款7:为多态基类声明virtual析构函数。

1)当derived类对象经由一个base指针被删除时,而该base类带有一个non-virtual析构函数,其结果未定义——通常对象的derived成分没被销毁。

2)经验:任何class只要带有virtual函数都几乎确定需要一个virtual析构函数。

3)polymorphic(多态性性质的)base classes应用声明一个virtual析构函数。

4)classes的设计目的如果不是作为base class使用,或者不具备多态性,就不该声明virtual析构函数。


条款8: 别让异常逃离析构函数:

1)C++中,两个异常同时存在的情况下,程序若不是结束执行就是导致为定义行为;如果析构函数不捕获异常并且析构函数本身的调用都是源于其他异常的抛出(即使正在处理这个异常),那么terminate函数将被调用;C++中抛出一个异常并且未得到处理则将调用terminate函数终止程序的运行。

2)析构函数绝对不要抛出异常。如果一个析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序。

3)如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)调用该操作。


条款9: 绝不在构造函数或析构函数中调用virtual函数:

1)base class在构造和析构期间不要调用virtual函数,因为virtual函数不会下降到derived class阶层。

2)derived class对象的base class构造期间,对象的类型是base class而不是derived class。

3)一旦derived class析构函数开始运行,对象内的derived class成员变量便呈现未定义值,所以c++视它们不再存在。进入base class析构函数后对象就称为一个base class对象。

4)在构造期间,无法使用virtual 函数从base classes向下调用,可以用令“derived class将必要的信息向上传递给base classes构造函数”来弥补。



条款10 令operator=返回一个reference to *this:

*为了连锁赋值(即obj1=obj2=obj),赋值操作符应该返回reference to *this。


条款11在operator中处理“自我赋值”:


(1)赋值操作符存在的问题:自我赋值(证同测试解决)和异常安全性。如:

Base& Base::operator=(const Base& rhs)

{

delete pb;//问题1,可能出现自我赋值,即rhs与*this可能是同一对象。

pb=new PB(*rhs.pb);//问题2:new PB可能会导致异常。

return *this;

}

(2)确保对象自我赋值时operator=有良好的行为的技术:


*证同测试(identity test):比较来源对象和目标对象的地址(只解决自我赋值,不解决异常安全)。


*精心周到的语句安排。如:

Base& Base::operator=(const Base& rhs)

{//不高效但行得通。

Base *temp=pb;//记住原理的pb

rhs=new PB(*rhs.pb);

delete temp;

return *this;

}

*copy and swap技术:Base提供一个swap函数。

Base& Base::operator=(const Base& rhs)

{

Base temp(rhs);

swap(temp);

return *this;

}

Base& Base::operator=(Base rhs)

{

swap(rhs);

return *this;

}


条款12 赋值对象时勿让其每一个成分:


(1)Copying函数(copy构造函数和copy assignment操作符)应该确保复制"对象内所有成员变量"及"所有base class成分"。

(2)不要尝试以某个Copying函数实现另一个Copying函数。应当将其共同代码放入一个新的成员函数共两个Copying函数调用。


原创粉丝点击