effective c++第二篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liunan199481/article/details/82014531

第二篇:构造、析构、赋值运算

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

  • 编译器可以给类自动创造default构造、copy构造函数、析构、copy assignment操作符函数
  • 前提是你缺省了这些函数的声明和定义
  • **在类内如果有引用类型(referrence)和const类型的成员变量的话,编译器不会提供默认的赋值操作符函数,需要自己写

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

  • 将函数声明为private,以copy构造函数和赋值操作符为例,声明为private就可以阻止类外部调用,从而可以实现禁止拷贝的操作。
  • 上述方法,成员函数和友元函数还是能调用,还不是完全安全的,所有有一个实践上的推荐,就是声明为private,声明但是不实现。
  • 第二种方法,是声明一个base class,该class继承自base class,base class中的构造函数和copy assignment操作符函数为private,那么要是调用改class的构造函数或赋值操作符,编译器会去调用base class中的相应函数,因为是private所以被阻止。
class BaseClass
{
    private:
        BaseClass(const BaseClass&);
        BaseClass& operator=(const BaseClass&);
};
class ChildClass:public BaseClass{
};
  • 而且你并不一定需要public继承,而且BaseClass的析构也不一定要是virtual

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

  • 这点比较好理解,分为一下2点
  • 带多态性质的base class,需要一个virtual析构函数。如果一个类有一个virtual函数的话,那么就是希望它成为一个base class,它就应该有一个virtual析构。
  • 反之,如果一个class的设计目的不是为了成为base class,或者不是为了具备多态性,那么这个类就不需要virtual函数和virtual析构。
  • virtual析构的作用:一个父类指针指向一个子类对象,如果父类析构不是virtual,delete父类指针,只能销毁父类的内存,不能销毁子对象的内存,造成内存泄漏;若父类析构就可以解决这个问题,析构是从最深层的子类析构开始,往上调。

析构函数不要处理异常

  • 析构函数不能吐出异常,因为这样可能导致程序异常结束,资源未正常释放
  • 析构函数绝对不要吐出异常。如果一个被析构调用的函数吐出异常,析构应该捕捉异常,然后吞掉异常或结束程序。
  • 如果程序一定要对某异常做出反应,那么因该由普通函数去做,而不是析构函数。

绝不在构造和析构过程调用virtual函数

  • 原因:因为它永远不会下降到derived class,调用的函数base class的函数
  • 另一好理解的说法:在base class构造期间,virtual函数不是virtual函数。
  • 解决:如果想向base class构造函数传数据,可以在derived class构造函数初始化列表内,初始化base class构造函数,并传数据进去。

令operator=返回一个reference to *this

  • 为什么?要想能连续赋值,就需要这样,这也是一个习惯约定。
class Test;
Test& operator=(const Test&);

*这个约定也适用于所有的与赋值操作符相关的操作

Test& operator=(int rhs);

在operator=中处理自我赋值

class Test{};
Test t;
t=t;
  • 上面就是自我赋值,这是合法的
Test* p1=t;
Test* p2=t;
*p1=(*p2);
  • 虽然p1,p2不是一个变量,但是他们指向同一个对象,这丫是潜在的自我赋值
  • 类似的,数组元素间的赋值也可能是自我赋值比如:a[i]=a[j], 当i=j的时候
  • 解决办法:加上证同测试,如下:
Test& operator=(const Test& rhs){
    if(this ==&rhs) return *this;
    //....
}
  • 确定任何函数如果操作多个对象,而其中有多个对象是同一个对象时,其行为一定正确。可能出现的最典型的错误就是delete对象一次以上

复制对象时,勿忘记每个成分

  • coping函数时,勿忘记对象内所有成员变量和base class里的成员变量
  • 不要使用一个coping函数实现另一个coping函数,要将共同机能放在一个函数内,再分别调用。

猜你喜欢

转载自blog.csdn.net/liunan199481/article/details/82014531