• 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;
    }

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



  • 相关阅读:
    数据库表结构变动发邮件脚本
    .net程序打包部署
    无法登陆GitHub解决方法
    netbeans 打包生成 jar
    第一次值班
    RHEL6 纯命令行文本界面下安装桌面
    C语言中格式化输出,四舍五入类型问题
    I'm up to my ears
    How to boot ubuntu in text mode instead of graphical(X) mode
    the IP routing table under linux@school
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5165996.html
Copyright © 2020-2023  润新知