码迷,mamicode.com
首页 > 其他好文 > 详细

EC读书笔记系列之3:条款5、条款6、条款7

时间:2015-10-27 23:56:21      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:

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

记住:

★编译器可以(仅仅是可以,并非必须,仅当程序中有这样的用法时才会这么做!!!)暗自为class创建default构造函数,copy构造函数,copy assignment操作符以及析构函数。

 --------------------------------------------------------------------------------------------------------------------------------------------

  当你写一个空类,编译器会为其声明(仅仅是声明!!!)default构造函数,copy构造函数,copy assignment操作符和析构函数,它们都是public且inline。唯有当这些函数被需要(被调用),它们才会被编译器真正创建出来。

   

  对于copy constructor和copy assignment操作符,编译器创建的版本只是单纯地将来源对象的每个non-static成员变量拷到目标对象。

 

特殊情形:

    对于内含reference或者const成员的class,编译器会拒绝为其生成copy assignment操作符。若你打算这种类支持assignment操作,就必须自己定义copy assignment操作符。还有一种情况:若某个bases classes将copy assignment操作符声明为private,编译器将拒绝为其derived classes生成一个copy assignment操作符。毕竟编译器为derived classes所生的copy assignment操作符想象中可以处理base class成分,但它们当然无法调用derived class无权调用的成员函数。

 

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

记住:

★为驳回编译器自动(暗自)提供的功能,可将相应的成员函数声明为private并且不予实现。使用像Uncopyable(下面会讲)这样的base class也是一种做法。

 --------------------------------------------------------------------------------------

  借由声明一个成员函数,可阻止编译器暗自创建其专属版本(注意所有编译器产出的函数都是public);而令这些函数为private,可以阻止人们调用。但即使这样,member functions和friend函数还是可以调用你的private函数,解决方法是,仅声明这个private函数而不去定义,这样在不慎调用时会发生连接错误。(C++ iostream程序库中阻止copying行为就是这么做的!!!)

 

  另一种方法所谓的可将连接期错误移至编译期(好事,毕竟越早侦测出错误越好):

class Uncopyable { //Uncopyable的使用颇为微妙!!!

    protected:
        Uncopyable() {}
        ~Uncopyable() {}
    
    private:
        Uncopyable( const Uncopyable & );
        Uncopyable& operator=( const Uncopyable& );
};

class HomeForSale : private Uncopyable {
    //这样这个class就不用再声明私有的copy构造函数和
    //copy assignment操作符
};

  这样的话,只要任何人--甚至是member函数或friend函数--尝试拷贝HomeForSale 对象,编译器便试着生成一个copy构造函数和一个copy assignment操作符,而且这些函数的“编译器生成版”会尝试调用其base class的对应兄弟,而那些调用会被编译器拒绝(这就将本在在连接期的错误移到了编译期!!!),∵其base class的拷贝函数是private。不过这样做的一个问题是:使用这项技术可能导致多重继承(∵往往还可能需要继承其他class),而多重继承有时会阻止empty base class optimization(EBO)。

 

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

记住:

★带多态性质的base classes应该声明一个virtual destructor。若class带有任何virtual函数,它就应该拥有一个virtual destructor。

★classes的设计目的若不是作为base classes使用,或不是为了具备多态性,就不该声明virtual destructor。

 -----------------------------------------------------------------------------------------------------------------------------------

  当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,实际执行时通常发生的是对象的derived成分没被销毁(局部销毁现象)。

 

  当class不企图被当作base class,就无需令其析构函数为virtual。因为这样会增加vptr所占用的空间,解释如下:

    欲实现出virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。此份信息通常由一个所谓vptr(virtual table pointer)指针指出。vptr指向一个函数指针数组(称vtbl,virtual table);每一个带有virtual函数的class都有一个相应的vtbl。当对象调用某一virtual函数,实际被调用的函数取决于该对象的vptr所指的那个vtbl,编译器会在其中寻找适当的函数指针。

 

  拒绝 继承一个标准容器或任何其他“带有non-virtual析构函数”的class  这样的诱惑!!!

 

  最好为抽象基类声明一个pure virtual destructor并提供空白定义,三个理由:

    由于有pure virtual函数,所以构成抽象基类;

    由于有个virtual destructor,所以无需担心析构函数的问题;

    至于为什么提供空白定义,可以解释如下:

    (析构函数的运作方式是,最深层派生的那个class其析构函数最先被调用,然后是其每一个base class的destructor被调用。编译器会在基类的derived classes的destructor中创建一个对基类析构函数的调用动作,所以你必须为这个函数提供一份定义,否则连接器会抱怨)

EC读书笔记系列之3:条款5、条款6、条款7

标签:

原文地址:http://www.cnblogs.com/hansonwang99/p/4915833.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有 京ICP备13008772号-2
迷上了代码!