標籤: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++ 筆記 (4)