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


    条款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中创建一个对基类析构函数的调用动作,所以你必须为这个函数提供一份定义,否则连接器会抱怨)

  • 相关阅读:
    iOS适配HTTPS,创建一个自签名的SSL证书(x509)具体步骤
    iOS UIWebView 访问https绕过证书验证的方法
    socket 同步阻塞传输数据与关闭
    cookie范例
    Cookie的实现
    服务器如何处理http请求
    Web 服务器与应用服务器的区别是什么?
    servlet
    Apache、Nginx与Tomcat的区别
    Http 请求处理流程
  • 原文地址:https://www.cnblogs.com/hansonwang99/p/4915833.html
Copyright © 2020-2023  润新知