標籤:解決 拷貝構造 protect mem 友元函數 自動產生 應用 ext 友元
如何禁止C++預設成員函數發表於 2016-03-02 | 分類於 C++ | 閱讀次數 17前言
前幾天在一次筆試過程中被問到C++如何設計禁止調用預設建構函式,當時簡單的想法是直接將預設建構函式聲明為private即可,這樣的話對象的確不能直接調用。之後查閱了《Effective C++》之後得到了比較詳盡的解釋。
瞭解C++的預設行為
當我們建立空類時,C++預設給我們產生了四種成員函數:
- 建構函式
- 解構函式
- 拷貝建構函式(copy)
- 重載=的拷貝函數(copy assignment)
因此,當你寫下如下的代碼:
那麼編譯器會自動產生:
class Empty{public: Empty(){...} //default建構函式 Empty(const Empty& rhs){...} //copy建構函式 ~Empty(){...} //解構函式 Empty& operator=(const Empty& rhs){...} //copy assignment操作符};
至於copy建構函式和copy assignment操作符是不是有效取決於類的成員變數,例如:如果類成員有const變數或者引用,那麼是不能重新賦值的。
拒絕使用編譯器自動產生函數
書中提到了一個實際的應用情境。在房子銷售時,每一套房子都是獨一無二的(地理位置,裝修等等),那麼顯然我們不想讓別人使用拷貝建構函式或者copy assignment操作符。但是如果我們不寫,那麼編譯器會自動產生。如果我們寫了就會可能讓別人利用。那麼該怎麼辦呢?
- 首先我們最自然的想法就是把這兩個函式宣告為私人,這樣別人調用的時候可能會報錯。我們的直覺是正確的。確實這樣做可以行得通。於是我們如此寫到:
class HomeForSale{public: ...private: HomeForSale(const HomeForSale& hfs){...} HomeForSale& operator=(const HomeForSale& hfs){...}};
- 當然那麼做並不是萬事大吉了。因為member函數和友元函數仍然能調用私人成員函數。那麼你可能又想到答案:我們無需定義成員函數,只需聲明即可:
class HomeForSale{public: ...private: HomeForSale(const HomeForSale&); HomeForSale& operator=(const HomeForSale&);};
那麼member成員函數和友元函數調用時,在編譯階段沒問題,在連結階段會報錯。那麼還有沒有更好的方案能夠讓代碼在編譯階段就能檢測出錯誤呢? 答案是肯定的。
class Uncopyable{protected: Uncopyable(){} //允許derived對象的構造和解析 ~Uncopyable(){}private: Uncopyable(const Uncopyable&); //但阻止copying Uncopyable& operator=(const Uncopyable&);};
那麼,為了阻止HomeForSale被拷貝,我們只需繼承Uncopyable:
class HomeForSale:private Uncopyable{ ...};
class HomeForSale{public: HomeForSale(const HomeForSale&) = delete; HomeForSale& operator=(const HomeForSale&) = delete;};
總結
如何禁止C++預設成員函數