标签:effective c++ 笔记 c++
//---------------------------15/03/29----------------------------
//#9 绝不在构造和析构过程中调头virtual函数
{
/*
1:在构造时调用virtual函数有两个结果
1>如果基类实现了这个函数,就调用基类的函数。
2>基类没有实现这个函数,链接时报错。
原因:
1>基类的构造函数 是早于 派生类的构造函数调用的,所以如果virtual函数使用派生类版本的
话,很可能用到未初始化的派生类的成员变量。c++为了不让你走这条危险的路,就会只调用基类的版本
2>根本原因:在调用基类构造函数时,对象类型是base class, 所以会调用基类版本。
所以不要在构造函数中调用任何virtual函数。
2:在析构函数中调用vitual函数:
由于派生类的析构函数是先于基类调用的,所以轮到基类的构造函数时,派生类的成员变量依旧呈现
未定义状态。所以c++视它们不存在,在调用基类析构函数时,对象称为一个base class对象。
3:为了在派生类对象创建时,基类中有适当版本的显示信息调用,一个解决办法是由派生类传入一个消息,
再调用non_virtual版本来显示。
*/
}
//#10 令 operator= 返回一个reference to *this
{
/*
关于赋值,c++中可以写成连锁形式:
int x,y,z;
x = y = z = 15;
为了实现这种连锁赋值,赋值操作符必须返回一个reference指向操作符的左侧实参。
*/
class Widget
{
public:
Widget& operator=(const Widget& rhs)
{
...
return *this;
}
};
}
//#11 在operator=中处理自我赋值
{
//看下面的函数
Widget&
Widget::operator=(const Widget& rhs)
{
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
//这样如果是自我赋值,那就先delete了pb,最后pb就指向一个已经删除的对象
//如果让operator=具备 异常安全性 往往自动获得自我赋值安全。
Widget& Widget::operator=(const Widget& rhs)
{
Bitmap* pOrig = pb;
pb = new Bitmap(*rhs.pb);
delete pOrig;
return *this;
}
//这么做会有效率问题:如果是自我赋值,那就多做了一次new以及delete;但是考虑到自我赋值的几率
//并不建议在开头加上if判断来判断是否是自己。而且用了if语句,效率会明显下降
//还有种方法是使用swap保证异常安全性
Widget& Widget::operator=(const Widget& rhs)
{
Widget temp(rhs);
swap(temp);
return *this;
}
}
//#12 复制对象时勿忘其每一个成分
{
/*
1:当你自己实现operator=操作时,如果你忘记了一个成员变量的复制,编译器不会警告你
2:当你写自己的operator=或者copy构造函数时应该记得:
1>复制所有的自己的成员变量
2>调用所有base classes内的适当的copying函数。
3:如果发现copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是
建立一个init成员函数,供两者调用。(但是考虑到前面的条目,构造函数直接初始化效率会很高,所以
如果相近的代码只是赋值的话,还是多动手的好)
*/
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
:Customer(rhs), priority(rhs.priority)
{
...
}
PriorityCustomer&
PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
...;
Customer::operator=(rhs);
prioriy = rhs.priority;
return *this;
}
}
标签:effective c++ 笔记 c++
原文地址:http://blog.csdn.net/boydfd/article/details/44735093