前言
如果系統自動生成的賦值運算子過載函式不合乎你的要求,那麼就應當定製自己的賦值運算子。
然而,定製賦值運算子有兩點是非常值得注意的,本文將講解這兩點,讓你寫出更優質的 =運算子。
第一點:請返回 reference to *this
我們經常使用如 "a=b=c=1" 這種形式的連鎖賦值語句,而過載的賦值運算子自然也應當能夠這樣使用。
因此,在過載運算子函式末尾請寫上如這樣的語句 return *this;
除了賦值運算子,+=,-=這樣的賦值運算子同樣需要這樣做。
第二點:處理好自我賦值
首先,我們看一段問題程式碼:
1 // 點陣圖資源類 2 class Bitmap { /*......*/ }; 3 4 // 點陣圖資源管理類 5 class Widget { 6 public: 7 //...... 8 Widget & operator=(const Widget & rhs); 9 //...... 10 private: 11 //...... 12 Bitmap *pb; // 點陣圖資源。指標型別,指向 heap 分配而得的空間 13 //...... 14 }; 15 16 Widget & Widget::operator=(const Widget & rhs) 17 { 18 delete pb; // 刪除原有資源 19 pb = new Bitmap(*rhs.pb); // 申請新的資源並存放右運算元的資料 20 return *this; 21 }
問題出在過載函式中,如果左右運算元是相同的物件,delete 掉原有資源之後,所有資料資訊就全丟了。
因此,運算子過載函式需要加上一個證同測試:
1 Widget & Widget::operator=(const Widget & rhs) 2 { 3 // 加入證同測試 4 if (this == &rhs) 5 return *this; 6 7 delete pb; // 刪除原有資源 8 pb = new Bitmap(*rhs.pb); // 申請新的資源 9 10 return *this; 11 }
但這依然不是最好的做法:因為 new 有可能失敗,導致資源丟失。
下面這個精心設計的過載函式才是我們需要的:
1 Widget & Widget::operator=(const Widget & rhs) 2 { 3 Bitmap * pOrig = pb; 4 pb = new Bitmap(*rhs.pb); 5 delete pOrig; 6 7 return *this; 8 }
這個實現就保證了賦值的安全,健壯,是個非常可取的方案。
小結
賦值運算子還有一些其他的非常可取的實現,這裡就不一一講解了。