• Effective C++ -- 构造析构赋值运算


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

    • 编译产生的析构函数时non-virtual,除非这个类的基类析构函数为virtual
    • 成员变量中有引用和const成员时,无法自己主动生成copy assignment函数
    • 基类将copy assignment操作符声明为private时。编译器拒绝为其derived classes生成一个copy assignment操作符。

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

    • 将自己主动生成的默认构造函数,拷贝构造函数,copy assignment声明为private
    • 声明为private并不绝对安全。成员函数和友元函数能够进行调用 -- 进行声明,但不定义(产生链接错误)
    • 定义一个基类。将默认构造函数,拷贝构造函数。copy assignment声明为private。由派生类继承该基类(产生编译错误。boost中的noncopyable类)

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

    • 基类指针指向派生类时,delete基类指针,无法调用到派生类的析构函数
    • 不论什么class仅仅要带有virtual函数,应该有一个virtual析构函数。

    • 当class不含virtual函数,通常表示它并不意图被用作一个base class。
    • 当class不企图被当做base class。其析构函数为virtual往往是个馊主意。(占用空间,减少效率)

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

    • 析构函数未捕获异常时,假设该类对象存储于容器中。产生异常后可能导致容器中的其它对象无法析构。
    • 析构函数须要捕获异常,某些引发异常的操作可移出析构,由客户调用进行处理

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

    • base class构造期间。virtual函数绝不会下降到derived class阶层。构造期间。virtual函数不是virtual函数。

    • 当base class构造函数运行时derived class成员变量尚未初始化,假设下降到derived class,derived class将会使用为初始化的local成员变量。

    • derived class对象的base class构造期间。对象的类型时base class。
    • 一旦derived class析构函数開始运行,进入base class析构函数后,对象类型被视为base class。


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

    为了实现连锁赋值,赋值操作符必须返回一个reference指向操作符左側实參。

    仅仅是协议,并不是强制。
    Widget& operator=(const Widget& rhs) {return  *this;}
    问题:
    能否够返回常量引用?

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

    • 须要解决自我赋值安全性和异常安全性


    class Bitmap {...};
    class Widget {
    private:
        Bitmap* pb;
    };
    
    Widget& Widget::operator=(const Widget& rhs)
    {
        delete pb;
        pb = new Bitmap(*rhs.pb);
        return *this;
    };

    • 以上代码问题:当自我赋值时,将删除自身的pb。构造新bp时。使用一个已删除的对象。

      解决方法例如以下:

    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.复制对象时勿忘其每个成分

    • 新加入成员变量时须要改动复制构造函数,copy assignment函数。

    class PriorityCustomer: public Customer {
    public:
        PriorityCustomer(const PriorityCustomer& rhs);
        PriorityCustomer& operator=(const PriorityCustomer& rhs);
    private:
        int priority;
    };
    
    PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):priority(rhs.priority)
    {
        log("");
    }
    
    PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
    {
        log("");
        priority = rhs.priority;
        return *this;
    }

    • 以上代码问题:未调用基类的拷贝构造函数,未调用基类的赋值操作符重载函数。正确代码例如以下:

    PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority)
    {
        log("");
    }
    
    PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
    {
        log("");
        Customer::operator(rhs);
        priority = rhs.priority;
        return *this;
    }

    • 无法在拷贝构造函数中调用基类的赋值操作符重载。无法在赋值操作符重载函数中调用基类的拷贝构造函数。



  • 相关阅读:
    【程序2】
    【程序1】
    基数排序
    归并排序
    选择排序
    leetcode15
    leetcode221
    leetcode322
    leetcode921
    leetcode922
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5165996.html
Copyright © 2020-2023  润新知