C++ 程式設計/類/良好類
一個“良好”的類考慮了以下函式的使用
1. 複製建構函式。
2. 賦值運算子。
3. 相等運算子。
4. 不相等運算子。
class Nice
{
public:
Nice(const Nice &Copy);
Nice &operator= (const Nice &Copy);
bool operator== (const Nice ¶m) const;
bool operator!= (const Nice ¶m) const;
};
一個“良好”的類也可以稱為容器安全類。許多容器,例如我們將在後面看到的標準模板庫(STL) 中的那些容器,在與你的類的物件互動時使用複製構造和賦值運算子。如果預設行為(按成員進行逐個複製,而不是按二進位制複製)不可取或不足以正確地複製/構造你的物件,則只需宣告和定義賦值運算子和複製建構函式。
一個普遍的經驗法則是,如果預設的按成員進行逐個複製操作不適用於你的物件,那麼你應該定義一個合適的複製建構函式和賦值運算子。如果兩者中任何一個被定義,則它們都需要。
複製建構函式的目的是允許程式設計師執行與賦值運算子相同的指令,特殊情況是知道呼叫者正在初始化/構造而不是複製。
在使用複製建構函式時使用 explicit 關鍵字也是一個好習慣,以防止意外的隱式型別轉換。
示例
class Nice
{
public:
explicit Nice(int _a) : a(_a)
{
return;
}
private:
int a;
};
class NotNice
{
public:
NotNice(int _a) : a(_a)
{
return;
}
private:
int a;
};
int main()
{
Nice proper = Nice(10); //this is ok
Nice notproper = 10; //this will result in an error
NotNice eg = 10; //this WILL compile, you may not have intended this conversion
return 0;
}
相等運算子表示“這個物件是否等於那個物件?”。 什麼構成相等由程式設計師決定。 這是如果你想用你類中的物件使用相等運算子的必要條件。
但是,在大多數應用(例如數學)中,通常情況下,對不相等進行編碼比對相等進行編碼更容易。在這種情況下,以下程式碼可以為相等編寫。
inline bool Nice::operator== (const Nice& param) const
{
return !(*this != param);
}
不相等運算子表示“這個物件是否不等於那個物件?”。 什麼構成不相等由程式設計師決定。 這是如果你想用你類中的物件使用不相等運算子的必要條件。
但是,在某些應用中,對相等進行編碼比對不相等進行編碼更容易。在這種情況下,以下程式碼可以為不相等編寫。
inline bool Nice::operator!= (const Nice& param) const
{
return !(*this == param);
}
如果關於(不)相等運算子具有不同效率(無論哪種)的陳述對你來說完全是胡說八道,請考慮通常,所有物件屬性必須匹配,兩個物件才能被認為是相等的。
通常,只有當兩個物件要被認為是不相等時,一個物件屬性必須不同。對於相等和不相等運算子,這並不意味著一個是比另一個更快的。
但是,請注意,使用上面定義的相等和不相等函式會導致無限遞迴迴圈,因此必須小心,只使用其中一個。此外,還有一些情況是兩者都不適用,因此上面兩種方法都無法使用。
給定兩個物件 A 和 B(具有類屬性 x 和 y),相等運算子可以寫成
if (A.x != B.x) return false;
if (A.y != B.y) return false;
return true;
而不相等運算子可以寫成
if (A.x != B.x) return true;
if (A.y != B.y) return true;
return false;
所以,是的,相等運算子當然可以寫成...!(a!=b)...,但它並沒有更快。事實上,這裡還增加了方法呼叫和否定操作的開銷。
因此問題變成了,少量執行開銷是否值得更小的程式碼和更好的可維護性?對此沒有簡單的答案,它完全取決於程式設計師如何使用它們。如果你的類包含,比如,一個包含 10 億個元素的陣列,那麼開銷是微不足道的。