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

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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
有效的基于模型的系统工程(MBSE)光盘是一种集成了各种系统工程方法和工具的工具。它是为了帮助系统工程师在整个工程开发过程中实现更高效、更可靠的系统设计和开发而设计的。 MBSE光盘的主要优势之一是它提供了一个共享和集成的平台,使得系统工程师可以更好地协同工作和沟通。通过使用光盘上的模型和工具,系统工程师们可以更快地理解和分析系统需求,并作出更准确的决策。此外,光盘还可以帮助系统工程师们更好地管理项目,跟踪进度,并及时发现和解决问题。 MBSE光盘还可以通过自动化生成各种文档和报告来加快文档编写的速度。系统工程师可以使用光盘上的模型和工具来自动生成需求规格书、系统设计文档等。这样不仅可以提高文档编写的效率,还可以减少错误和重复工作。 此外,有效的MBSE光盘还可以帮助系统工程师们更好地进行系统仿真和验证。通过使用光盘上的仿真工具,系统工程师们可以模拟系统的性能和行为,预测系统在不同条件下的工作情况,并进行必要的优化。 综上所述,有效的基于模型的系统工程光盘是一个集成了各种工具和方法的平台,可以使系统工程师在项目开发中更好地协同工作、更准确地分析和决策,并加快文档编写的速度。它还可以帮助系统工程师们进行系统仿真和验证,以确保系统设计的可靠性和可行性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值