2014年9月29日 星期一

C++沉思錄//第四章整理

class design checklist

  • 你需要一個建構子嗎?
想一下。
  • 你的成員變數是私有的嗎?
以函數當作存取成員變數的好處:
1. 定義域、值域的程式化。ex: length的長度一定要大於零。
2. 算式表示抽象屬性。ex: vector<int>::length(); 元素的數量是取值時才運算出來的。
  • 你的類別需要一個無參數的建構子嗎?
利用無參數建構子用來定義成員變數的「預設初始化狀態」。
  • 是不是每個建構子都初始化所有的成員變數呢?
雖然建構子是初始化所有的成員變數,但其實在真實世界的例子中,也不是這麼一定。
這問題是刺激你思考是否都盡可能的初始化了。
  • 類別需要解構子嗎?
思考:
1. 這個類別要做些什麼
2. 是否有不會由成員函數自動釋放的動態記憶體空間
通常,建構子有new出什麼動態記憶體配置,解構子就要delete
  • 類別需要一個虚擬解構子嗎?
動態連結時,基礎類別指標是否有必要執行洐生類別的物件的解構子,為了釋放洐生類別的物件才有使用的動態記憶體空間
  • 你的類別需要自己寫一個複製建構子嗎?
複製該類別的物件,不相當於「複製其成員變數和基礎類別物件」,則需要複製建構子。
如果有動態記憶體宣告的空間,就考慮是否要複製建構子。
  • 你的類別需要自己寫一個賦值運算子嗎?
如果有複製建構子,大多需要建立一個。
注意返回值要 X& X::operator=(),並且 return *this;
  • 你的賦值運算子能正確的將物件賦值給物件嗎?
「自我賦值常常被錯誤的應用,不只是一本C++的書弄錯了」
賦值總是用新的值取代舊的值,但是如果「來源物件與目標物件是同一個」,就不可以奉行「先釋放舊值,再複製新值」,會先毀掉來源物件裡的值。
在這,有兩個作法

1. 判斷是不是賦值給自己,再決定是不是要delete
xString$ xString::operator=(const xString& xstr)
{
if (&s != this)
{
delete [] data;
data = new char[strlen(s.data) + 1];
strcpy(data, s.data);
}
return *this;
}
2. 先暫存,再賦值,最後再delete
xString$ xString::operator=(const xString& xstr)
{

char* newdata = new char[strlen(s.data) + 1];
strcpy(newdata, s.data);
delete [] data;
data = newdata;
return *this;
}
  • 你的類別需要關係運算子嗎?
只要用戶想要排序你的類,你就必須要提供關係運算子。
  • 刪除陣列時你記得使用delete[]嗎?
會保留這種奇怪的寫法,是為了和C語言相容,同時保有效率。

  • 記得在複製建構子和賦值運算子的參數加上const了嗎?
提供保證,複製物件並不會改變原物件。
  • 如果函數的參數是參考,它們是否該加上const?
只有當函數想改變參數時,才會取消加上const
  • 記得適當的宣告成員函數成const了嗎?
有設定唯讀的函數,才可以套用在STL的演算法中執行。

沒有留言:

張貼留言