Effective C++ 阅读笔记·Constructors, Destructors, and Assignment Operators

05 Know what functions C++ silently writes and calls

  • 定义一个类,编译器会为它声明一个copy构造函数,一个copy assignment操作符和一个析构函数;如果自己没有声明任何构造函数,编译器就会声明一个默认构造函数;所有这些函数都是public且inline;
//定义一个空类:
class Empty{};
//相当于如下定义:
class Empty{
    Empty(){...}
    Empty(const Empty& rhs){...}
    ~Empty(){...}
    Empty& operator=(const Empty& rhs){...}
}
  • C++不允许“让reference改指向不同对象”;
  • 更改const成员是不合法的;

06 Explicitly disallow the use of compiler-generated functions you do now want

  • 所有编译器产出的函数都是public;
  • 如果不想使用编译器自动生成的默认函数,必须自行声明它们;如果不希望这些函数被调用,可以将相应的成员函数声明为private,并且不予实现(主要针对copy assignment操作符);
  • 可以设计一个基类来实现阻止coping动作:
class Uncopyable{
protected:
    Uncopyable(){}         //允许derived对象构造和析构
    ~Uncopyable(){}
private:
    Uncopyable(const Uncopyable&);  //阻止copying
    Uncopyable& operator=(const Uncopyable&);
};
class HomeForSale:private Uncopyable{
    ... //子类不需要再声明copy构造函数和copy assign.操作符
}

07 Declare destructors virtual in polymorphic base classes

  • 任何class只要带有virtual函数,都需要将析构函数设置成virtual;带有多态性质的基类都应该声明一个虚析构函数;
  • 如果class不用作基类或不需要具备多态性,则不要将析构函数设置为virtual;
  • 每一个带有virtual函数的class都有一个相应的vtbl(virtual table),并有一个vptr(virtual table pointer)指针管理virtual函数调用,(该类增加一个指针变量);
  • pure virtual函数导致抽象类,也就是该类不能被实例化;

  • 多态性是一个接口多种实现,是面向对象的核心,分为类的多态性和函数的多态性;

  • 派生类的虚表(vtbl)中虚地址的排列顺序和基类的虚表中虚函数地址排列顺序相同;
  • C++中类的多态性可以简单描述为:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数,如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,就调用基类的函数;
  • 函数的多态性是函数名相同、参数不同的函数;当通过该函数名调用函数时,会根据参数不同来调用不同的函数;
  • 析构函数的运作方式是,最深层派生的类其析构函数最先被调用,然后是每一个基类的析构函数被调用;
  • 需要为纯虚析构函数提供定义:
class AW{
public:
    virtual ~AW()=0;
};
AW::~AW(){}

08 Prevent exceptions from leaving destructors

  • 析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序;
  • 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作;

09 Never call virtual functions during construction or destruction

  • 创建派生类对象时,会先调用基类的构造函数,然后才会去调用派生类的构造函数;进入基类构造函数之后会先去实例化基类的对象,然后才是派生类的对象;
  • 在子类对象的基类构造期间,对象的类型是基类,而不是子类;
  • 在构造和析构期间不要调用virtual函数,因为这类调用不会降至子类(比起当前执行构造函数和析构函数的那层);

10 Have assignment operators return a reference to *this

  • 令赋值操作符返回一个reference to *this;
  • 这样做的好处:
    1.返回引用可以节省资源,返回值不需要再调用构造函数;
    2.可以实现形如(x = y) = 3这样的连等操作,因为这样的写法要求赋值运算符返回的是可以修改的左值;
    3.STL和boost库中的标准代码都是这样写的,为了与它们相兼容;

11 Handle assignment to self in operator

  • 确保当对象自我赋值时operator=有良好的行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap;
  • 确定任何函数如果操作一个以上的对象,而其中许多个对象是同一个对象时,其行为仍然正确;

12 Copy all parts of an object

  • 不要令copy assignment操作符调用copy构造函数;
  • 不要在copy构造函数里调用copy assignment操作符;
  • copy函数应该确保复制“对象内的所有成员变量”及“所有base class成分”;
  • 不要尝试以某个copying函数实现另一个copying函数;应该将共同机能放进第三个函数中,并由两个copying函数共同调用;
  • 如果你的copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是,建立一个新的成员函数给两者调用。这样的函数往往是private而且常被命名为init。这个策略可以安全消除copy构造函数和copy assignment操作符之间的代码重复;
    相关博客:【1】
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值