构造/析构/赋值运算

Posted o-v-o

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了构造/析构/赋值运算相关的知识,希望对你有一定的参考价值。

构造/析构/复制运算

05.了解C++默默编写并调用哪些函数

  • 如果你没有声明,编译器就会为他声明一个copy构造函数,一个copy assiggnment操作符和一个析构函数,如果没有构造函数,编译器会为你声明一个default构造函数.所有这些都是public且inline.
class Empty {};

// 就像写下这样的代码
class Empty{
public:
    Empty() {...}                             // default 构造函数
    Empty(const Empty& rhs) {...}        // copy构造函数
    ~Empty() {...}                 // 析构函数,是否该是virtual稍后说明
    
    Empty& operator=(const Empty& rhs) {...} // copy assignment 操作符
};

// 编译器餐厨的析构函数是一个non-virtual,除非这个class的base class自身声明有virtual析构函数.
// 这种情况下这个函数的虚属性;virtualness;主要来自base class.
  • 注意: 编译器可以暗自为class 创建default构造函数,copy构造函数,copy assignment操作符,以及析构函数.

06.若不想使用编译器自动生成的函数,就该明确拒绝

  • 将成员函数声明为private而且故意不实现他们

    class HomeForSale{
    public:
        ...
    private:
        ...
        HomeForSale(const HomeForSale&);             // 只是声明
        HomeForSale& operator=(const HomeForSale&);
    };
    
    // 没有写函数参数的名称,参数名称并非必要,这个函数毕竟不会被实现出来,也很少被使用,没必要指定参数名称.
  • 将连接期错误移至编译期是可能的(而且是好事,毕竟越早侦测出错误越好),只要将copy构造函数和copy assignment 操作符声明为private就可以办到,但不是在HomeForSale自身,而是在一个专门为了阻止coping动作而设计的base class内.

    class Uncopyable{
    protected:                    // 允许derived对象构造和析构
        Uncopyable() {}
        ~Uncopyable() {}
    private:               // 阻止copying 
        Uncopyable(const Uncopyable&);
        Uncopyable& operator=(const Uncopyable&);
    };
    
    // 为求阻止HomeForSale对象被拷贝,我们唯一需要做的就是Uncopyable:
    class HomeForSale: private Uncopyable{
        ...
    };
    
    // 只要任何人--甚至是member函数或friend函数--尝试拷贝HomeForSale对象,编译器便试着生成一个copy构造函数和一个copy assignment操作符.这些函数的"编译器生成版"会尝试调用其base class的对应兄弟,那些调用会被编译器拒绝,应为其base class 的拷贝函数是private.

07.为多态基类声明virtual析构函数

  • polymorphic(带多态性质的)base classes 应该声明一个virtual析构函数.如果class 带有任何virtual函数,它就应该拥有一个virtual析构函数.
  • Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不该声明virtual析构函数.

08.别让异常逃离析构函数

  • 析构函数绝对不要吐出异常.如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下他们(不传播)或结束程序.
  • 如果客户需要对某个函数运行期间抛出的异常做出反应,那么class 应该提供一个普通函数(而非在析构函数中)执行该操作.

09.绝不在构造和析构过程中调用virtual函数

  • 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层).

10. 令operator=返回一个reference to * this

  • 令赋值(assignment)操作符返回一个reference to *this

11.在operator=中处理"自我赋值"

  • 确保当对象自我赋值时operator=有良好行为.其中技术包括比较"来源对象"和"目标对象"的地址,精心周到的语句顺序,以及copy-and-swap.
  • 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为任然正确.

12.复制对象时勿忘其每一个成分

  • copying 函数应该确保复制"对象内的所有成员变量"及所有base class成分.

  • 不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两个copying函数共同调用.

以上是关于构造/析构/赋值运算的主要内容,如果未能解决你的问题,请参考以下文章

链表:如何实现析构函数、复制构造函数和复制赋值运算符?

构造/析构/赋值运算

C++类和对象(构造函数析构函数拷贝构造函数赋值运算符重载Const成员)详细解读

C++类和对象(构造函数析构函数拷贝构造函数赋值运算符重载Const成员)详细解读

C++类和对象(构造函数析构函数拷贝构造函数赋值运算符重载Const成员)详细解读

构造析构赋值运算:条款5-条款12