Effect C++ 笔记 【2 Constructors Destructors and Assignment Operators】

2 赋值/析构/赋值运算

一个class, 一般都有一个或多个【构造函数】,一个【析构函数】,一个【拷贝赋值操作符】(copy assignment “=")。  他们是类的基础操作,必须确保他们的行为正确。

 

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

一个empty类,如果自己没声明,编译器会声明一个构造函数,一个【析构函数】,一个【拷贝构造函数】,和一个【拷贝赋值操作符】。 所有这些都是 public 且 inline的。

就像,如果写一个 class empty { };    //  就相当于写下了:


当这些函数被需要(调用)时,才被编译器创建出来。

default构造函数和析函数主要是给编译器一个地方用来放置”藏身幕后“的代码,像是调用base classes和non-static成员变量的构造函数和析构函数。

编译器产生的析构函数是 non-virtual 除非这个类的 base class 自身声明有 virtual 析构函数

    拷贝构造函数 和 拷贝赋值 只是单纯的将来源对象的每一个 non-static 成员变量拷贝到目标对象(内置类型编译器直接复制,自定义类型调用其拷贝构造函数)。

    但是,有几种情况编译器会拒绝编译这个赋值动作:
             1. class 内含有 reference成员。  C++不允许”让 reference 改指向不同对象“ 。     // 不太理解什么情况下class内会有const成员和reference成员
             2. class 内含有 const 成员。
             3. 基类将 拷贝赋值操作符 声明为 private。

    TIps
    : 1. 注意析构函数的 virtual

               2. 拷贝构造/拷贝赋值 注意 class中 是否有 引用和const 成员。

     

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

    比如,你不声明copy构造函数,那编译器就会为你制造一个。 如果你不想要这种自动生成的函数,就需要使用下面的方法:
         因为所有编译器产出的函数都是public , 为了阻止这些函数被创建,你得自行声明它们(而不实现),并声明为 private, 使你得以成功阻止人们调用它。(private 成员函数只能在该类定义内部使用。对象不能调用)   C++ iostream程序库中阻止copying行为就是这么干的。
         还可以,在一个专门阻止copying动作和设计的 base class内,声明这种函数。然后,让我们需要这种行为的类继承它。// uncopyable class 的运用比较微妙。设计多继承等等,有需要看书吧。

     

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

    局部销毁问题:当derived class 对象经由一个 base class 指针被删除,而该 base class 带着一个 non-virtual 析构函数,其结果未有定义——执行时通常是 对象的 derived 成分没被销毁。

    任何class只要带有 virtual 函数,几乎确定应该有一个 virtual 析构函数 。  但给不含virtual函数的class,定义 虚析构函数 是个馊主意。 // class不含virtual ,通常表示它并不意图做一个base class。

    [ 要是先出virtual函数,对象必须携带某些信息:C++实现virtual函数,对象用一个(virtual table pointer)指针指出调用哪个虚函数。vptr指向一个由函数指针构成的数组 vtbl (virtual table); 每一个带有虚函数的class都有一个相应的vtbl。]

    // 如果一个class 含有两个int成员(32bit),加入vptr后对象体积可能会增加50%~100%。这个类就不再具有移至性。

    【心得】: 当class内含至少一个virtual函数,才为它声明 virtual 析构函数

    【当心】:class不带 virtual 函数,你用它作为基类,可能会导致错误 (比如标准string不含任何virtual函数,但程序员错误的用它作为基类派生一个 specialString 类,可能会导致局部销毁的问题)


    【虚析构方式】: 最深层的那个class析构函数最先被调用,然后逐级向上找base的析构。  如果用 pure virtual(纯虚函数的 析构),记得必须为pure virtual提供一份定义,否则链接报错。

    Tips:   1. 带多态性的 base classes 应该声明一个 virtual 析构函数。

              2. Classes 设计的目的如果不是作为 base classes使用,或者不是为了 具备多态性, 就不该声明 virtual 析构函数。

     

    条款08:别让异常逃离析构函数   //这个理解不深

    两个异常同时存在的情况下,程序若不结束执行 会导致不明确行为。

    Tips: 1. 析构函数不要吐出异常。 如果一个被析构函数调用的函数可能抛出异常,在析构函数内 应该捕捉任何异常,然后吞下他们(不传播)或结束程序。

     

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

    在 base class 构造期间, virtual 函数不是 virtual的。(构造base class期间,derived class 成员变量尚未初始化。如果此期间virtual下降到derived层,要知道derived class的函数几乎必然取用local成员变量)

     

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

    内置类型和标准程序库提供的类型都这么做的。

     

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

    确保当对象自我赋值时 operator= 有良好的行为。 方式包括:   1. 比较来源和目标对象地址;2. 精心调整语句顺序;3. copy and swap。

     

     

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

    任何时候只要为“derived class 撰写 copying 函数”,必须小心也复制其base class成分。 那些成分往往是private,所以你无法直接访问。应该让derived class 的 copying函数调用相应的base class 函数:

    Tips:

    1. Copying 函数应该确保复制“对象内的所有成员变量”及“所有 base class 成分”。

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

    3. 拷贝赋值和拷贝构造函数 不要互相调用。如有重复机能,也放到第三个函数中

    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值