Effective C++ 笔记2

来源:互联网 发布:市政给排水设计软件 编辑:程序博客网 时间:2024/06/04 19:54

本文内容基本来自于《Effective C++》一书,为学习后的笔记,以便温故。


《Effective C++ 》第 2节  构造/析构/赋值运算符

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

    C++编译器会为一个空类声明一个copy构造函数,一个copy assignment操作符和一个析构函数。此外,如果没有声明构造函数,编译器会为你声明一个default构造函数。所有这些函数都是public inline。

     default构造函数和析构函数用来存放“隐藏幕后”的代码。copy构造函数和copy assignment操作符只是单纯的将来源对象的每一个non-static成员变量拷贝到目标对象。但是要注意三点:

    a:如果打算在一个内含reference成员的class支持赋值操作,你必须自己定义copy assignment操作符。因为C++不允许让reference改指向不同的对象

    b:若类中使用const成员,因为更改const成员是不合法的。所以也需要自已实现copy assignment操作和copy构造函数

    c:如果某个base classes将copy assignment操作符声明为private,编译器将拒绝为其derived classes生成一个copy assignment操作符。

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

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

    Uncopyable作为base class方法

    class Uncopyable{

      protected:

          Uncopyable(){};

          ~Uncopyable(){};

     private:

        Uncopyable(const Uncopyable&);

      Uncopyable& operator= (const Uncopyable&);

    };

    其他的类private继承Uncopyable

    class HomeForSale: private Uncopyable{

          ............/////////     

};

   这样就不能对HomeForSale使用copy构造函数和copy assignment操作符了

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

     C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义,实际上执行时通常发生的是对象的derived成分没有被销毁。只执行了其base class 的析构函数,造成了局部销毁资源的状况。从而造成了内存泄露。

    解决这个问题的做法很简单:给base class一个virtual析构函数。此后删除derived class对象就会如你想要的那般。它会消除整个对象,包括base class成分。如:

   class BaseClass{

    BaseClass(){};

    virtual  ~BaseClass(){ cout<<"~BaseClass()"<<endl;}  

};

  class DrivedClass: public BaseClass{

  DrivedClass(){} 

 ~DrivedClass(){ cout<<"~DrivedClass()"<<endl;}  

};

BaseClass* pBaseClass = new DrivedClass();

delete pBaseClass; //现在不会出现局部删除的现象。

如果class不含virtual函数,通常表示它并不意图被用作一个base class。当class不企图被当做base class,令其析构函数为virtual函数往往是个馊主意。这样做会使得对象会携带某些不必要的信息,用来运行期决定哪一个virtual函数该被调用。 

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

(4) 条款08:别让异常逃离析构函数

       在析构函数中出现异常,会导致程序过早的结束,造成某些资源的泄漏,例如:应该delete某些对象,但是没有执行到。

      a:析构函数绝对不要吐出异常,如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或者结束程序(abort)

      b:如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数执行该操作。

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

       base class在构造函数或者析构函数中如果使用vritual函数,那么该base class调用的也是自身的virtual函数,而不会降级为derived class 相应的virtual函数。

      记住这类调用从不下降至derived class。

(6)条款10:令operator= 返回一个reference to *this

     注意,这只是一个协议,并不一定必须遵循它。然而这分协议被所有内置类型和标准程序库提供的类型如:string ,vector, complex等共同遵守。

(7)条款11:在operator=中处理“自我赋值”

      确保当对象自我赋值时operator=有良好行为,其中技术包括比较“来源对象”和“目标对象”的地址,精心周到的语句顺序,以及copy-and-swap

      确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。

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

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

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


原创粉丝点击