【Effection C++】读书笔记 Part2 构造/析构/赋值运算
条款09:绝不在构造和析构函数中调用virtual函数
构造函数和析构函数期间不要调用virtual函数,虽然语法上并不会有错误。但是在一个派生类的基类成分构造期间,对象的类型永远是基类而不是派生类。包括使用typeid或者dynamic_cast都会将对象视为基类类型,所以其调用的虚函数是永远不会下降到派生类的。
对于析构函数也有着类似的行为,派生类的成员在析构的时候,其类型也是随着析构函数的执行而不断变化,先是派生类类型然后是基类类型。
如果基类构造函数需要派生类的信息,可以通过派生类构造函数时候,将必要的信息传送到基类的构造函数。
条款10:令operator=返回一个“reference to *this”
为了实现连锁赋值,赋值运算符必须返回一个reference指向操作符的左侧实参。
class Widget
{
public:
Widget & operator=(const Widget &rhs)
{
...
return *this;
}
}
Widget d1,d2,d3;
d1 = d2 = d3; //实现连锁赋值
条款11:在operator=中处理自我赋值
- 确保当对象自我赋值的时候operator=有良好行为。其中技术包括比较:
- 比较源对象和目标对象的地址,可以保证自我赋值,但是可能无法保证异常安全
- 设置语句程序使得保证自我赋值和异常安全性
- copy-and-swap技术
- 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时候,其行为仍然正确。
条款12:复制对象时勿忘其每一个成分
- Copying函数应该确保复制“对象内的成员变量”及“所有base class成分”。
- 不要尝试以某个coying函数实现另外一个函数,应该将所有共同机能放进第三个函数中,并由两个copying函数共同调用。
class Cutsomer
{
……
private:
string name;
string telphone;
};
class PriorityCustomer:public Cutsomer
{
public:
PriorityCustomer() { }
PriorityCustomer(const PriorityCustomer& rhs);
PriorityCustomer& operator=(const PriorityCustomer& rhs);
private:
int priority;
};
PriorityCustomer(const PriorityCustomer& rhs)
:Cutsomer(rhs),priority(rhs.priority) //拷贝初始化初始化基类部分
{
cout<<"PriorityCustomer Copy Ctor"<<endl;
}
PriorityCustomer& operator=(const PriorityCustomer& rhs)
{
cout<<"PriorityCustomer assign operator"<<endl;
//对基类对象进行赋值操作
Cutsomer::operator=(rhs);
priority=rhs.priority;
return *this;
}