条款8:别让异常逃离析构函数
在定义本类时出现的异常,应该在析构函数中捕获或者在析构函数中考虑在出现异常时强制结束程序。如果想要针对异常作出相应,可以考虑将出现异常的代码块放到一个普通函数中。
条款9:绝不在构造和析构过程中调用virtual函数
由于virtual函数的机制是动态绑定,根据实际的对象确定要调用的是基类还是子类的函数,此时需要知道的是对象已经存在,即构造函数是确定的,所以,构造函数不可以声明为virtual的。同理,析构过程中也不可以调用virtual函数,因为析构后的对象不复存在,所以不可以再发生动态绑定的机制。注意,这里说的是析构过程中,并不是说析构函数,析构函数是可以声明为virtual的。
条款10:令operator= 返回一个reference to *this
返回引用和非引用的区别就是引用返回的是一个对象,是一个变量,非引用返回的是一个值。通常,变量可以作为左值也可以作为右值,而值只可以作为右值。所以返回引用,可以作为左值存在,进而可以实现连续赋值的操作。这里不仅是=运算符,所有实现重载的运算符我们都会返回引用,因为没准你什么时候就需要将赋值后的结果作为左值存在了呢。
条款11:在operator= 中处理“自我赋值”
重载赋值运算符时需要考虑对象自我赋值的情况。以实例来说:
class Bitmap{...};
class Widget{
...
private:
Bitmap* pb;
};
Widget& Widget::operator=(const Widget& rhs)
{
if(this==&rhs){
return *this;//证同测试
}
Bitmap* temp=pb;//临时保存
pb=new Bitmap(*rhs.pb);//pb指向新地址
if(temp!=NULL){//删除旧地址
delete temp;
temp=NULL;
}
return *this;
}
条款12:复制对象时勿忘其每一个成分且不要尝试以某个copying函数实现另一个copying函数
copying函数指拷贝构造和copy赋值。这个条款说的是,在拷贝构造或者构造时不要忘记对类的每一个成员变量都进行赋值和复制,尤其是作为基类派生出来的子类时,尤其不要忘记在子类中对基类赋值和复制。以实例来说,请注意其他颜色的代码部分:
class Customer{
public:
...
private:
std::string name;
};
class PriorityCustomer:public Customer{
public:
...
PriorityCustomer(const PriorityCustomer& rhs);
PriorityCustomer& operator=(const PriorityCustomer& rhs);
private:
int priority;
};
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority){
........
}
PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs){
.......
Customer::operator=(rhs); //对base类进行赋值操作
priority=rhs.priority;
return *this;
}
当copying函数中有重复的代码时,你不想重复写,请不要尝试以某个copying函数实现另一个copying函数,可以考虑将代码共同的部分抽出封装成一个函数,一般叫init函数,在copying函数需要的地方进行调用。