【effective c++】构造/析构/赋值运算

条款5:了解c++默默编写并调用哪些函数

如果自己没声明,编译器会声明一个copy构造函数,一个copy赋值操作符和一个析构函数。此外,如果没有声明任何构造函数,编译器会声明一个default构造函数(如果已经声明了构造函数,编译器不会创建default构造函数)。编译器生成的所有这些函数都是public且inline

如果你打算在一个内含引用成员或const成员的class内支持赋值操作,你必须自己定义copy赋值操作符,因为c++并不允许让引用改指向不同对象,或者更改const成员,所以编译器不知道如何在自己生成的赋值操作符中处理它们。

如果某个base class将copy赋值运算符声明为private,编译器将拒绝为其派生类生成一个copy 赋值运算符,因为编译器为派生类生成的copy赋值运算符必须可以处理base成分,但它们无法调用派生类无权调用的成员函数。

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

声明一个成员函数,可以阻止编译器创建default版本,令函数为private,可阻止类的用户调用它。为了防止成员函数和友元函数调用前述private函数,可以只声明不定义,这样如果试图调用一个未定义的函数,会产生链接错误。

为了将上述链接错误转移至编译期,可以设计一个专门阻止copy动作的base class,在该class中将copy相关操作声明为private且未定义,然后其他需要阻止copy动作的类继承自该base class。因为派生类中编译器生成的copy构造函数和copy赋值运算符会调用基类的copy构造函数和copy赋值运算符,编译错误。

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

当派生类对象经由一个基类指针被删除,而该基类的析构函数是non-virtual,其结果未定义)(实际执行时通常发生的是对象的派生类成分没被销毁,造成资源泄漏

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

在派生类对象的基类成分构造期间(调用基类的构造函数),对象的类型是base class而不是derived class。相同道理也适用于析构函数,进入base class析构函数后对象就成为一个base class对象,而c++的任何部分包括虚函数,dynamic_cast等也都那么看待它。

在构造和析构期间不要调用virtual函数,因为这类调用都是调用的base class中的函数,不会调用当前class中的相应函数

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

为了实现链式赋值,赋值操作符必须返回一个reference指向操作符的左侧实参。这条规则适用于所有赋值相关运算,包括+=, -=, *=等

条款11:在operator= 中处理自赋值

class Bitmap {};
class Widget {
private:
    Bitmap *pb;
    Widget& operator= (const Widget &rhs);
};

// 处理了自赋值,但是如果new Bitmap导致异常,Widget会持有一个指针指向一块被删除的Bitmap
Widget& Widget::operator= (const Widget &rhs) {
    if (this == &rhs) {
        return *this;
    }

    delete pb;
    pb = new Bitmap(*rhs.pb);
    return *this;
}

// 如果new Bitmap跑出异常,pb保持原状
Widget& Widget::operator= (const Widget &rhs) {
    if (this == &rhs) {
        return *this;
    }

    Bitmap *pOrig = pb;
    pb = new Bitmap(*rhs.pb);
    delete pOrig;
    return *this;
}

条款12:复制对象时勿忘其每一个成分

当你编写一个copying函数(copy构造和copy赋值),请确保 1)复制所有local成员变量  2)调用所有base class内的适当的copying函数,如果不显式调用基类的copying函数,派生类对象的基类成分会被基类的default构造函数初始化

 

posted @ 2017-07-30 19:25  合唱团abc  阅读(291)  评论(0编辑  收藏  举报