(1)、默認構造函數c++
Empty(){...} //調用父類構造函數,non-static成員變量構造函數,不會默認初始化內置類型
(2)、析構函數ide
~Empty(){...} //調用父類析構函數,non-static成員變量析構函數
(3)、拷貝構造函數函數
Empty(const Empty& rhs){...} //單純地未來源對象的每個non-static變量拷貝到目標對象
(4)、賦值構造函數this
Empty& operator=(const Empty& rhs){...} //單純地未來源對象的每個non-static變量拷貝到目標對象
當類內有引用、const、及父類的拷貝構造函數,賦值構造函數爲private時,編譯器會拒絕生成這一類函數。換言之,若是類內有引用、const成員變量,或者其父類的相關函數不可訪問時,必須手動生成。有指針類型變量時,存在「深拷貝、淺拷貝」問題!!!spa
class Empty: { public: Empty(){...} Empty(const Empty& rhs){...} ~Empty(){...} Empty& operator=(const Empty& rhs){...} private: const int m_cInt; //只讀成員變量 int &ref; //引用型成員變量,必須在每一個構造函數手動初始化 };
禁止被拷貝構造或賦值構造的作法:設計
(1)、將相應成員函數聲明爲private且不去實現它。(連接期出錯)指針
class HomeForSale { public: HomeForSale(); ~HomeForSale(); private: HomeForSale(const HomeForSale& rhs); //只有聲明 HomeForSale& operator=(const HomeForSale& rhs); };
(2)、private繼承Uncopyable類(編譯期出錯)c++11
class Uncopyable { public: Uncopyable(){}; ~Uncopyable(){}; private: Uncopyable(const Uncopyable& rhs); Uncopyable& operator=(const Uncopyable& rhs); };
(1)、polymorphic(帶多態性質的)base classes應該聲明一個virtual析構函數,這樣經過delete 基類指針時,也會調用其指向對象的析構函數。避免內存泄漏。若是一個class帶有一個或多個virtual函數,它就應該擁有一個virtual析構函數。code
(2)、classes的設計目的若是不是做爲base classes使用,或不是爲了具有多態性,就不該該聲明virtual函數。(會多出一個vptr指針,佔用內存),string及STL容器均爲無virtual函數!儘可能別繼承它們作事。對象
引伸:c++11中能夠override,final關鍵字指定。只能做用於虛函數
override,表示此虛函數一定「重寫」了基類中的對應虛函數。
final,(1)做用在虛函數:表示此虛函數已處在「最終」狀態,後代類一定不能重寫這個虛函數。
(2)做用在類:表示此類一定不能被繼承
編譯器將幫你檢查是否「一定」
(1)、析構函數絕對不要拋出異常,若是一個被析構函數調用的函數可能拋出異常,析構函數應該捕捉任何異常,而後處理它們,或者結束程序;
(2)、若是接口使用者須要對某個操做函數運行期間拋出的異常做出反應,那麼class應該提供一個普通函數(而非在析構函數中)執行該操做;
class DBConn { public: void close() { db.close()//可能拋出異常函數 closed = true; } ~DBConn() { if (!closed) //若是客戶沒有主動關閉的話 { try { db.close(); } catch(...) { //製做運轉記錄,記下對close的調用失敗 } /* code */ } } private: DBConnection db; bool closed; };
class Transaction //基類 { public: Transaction(); ~Transaction(); virtual void logTransaction const = 0; }; Transaction::Transaction() { ... logTransaction();//記錄這筆交易 } class BuyTransaction : public Transaction { public: BuyTransaction(); ~BuyTransaction(); virtual void logTransaction()const override; //記錄這筆交易 };
BuyTransaction b;時先執行Transaction::Transaction,此時傳入的this指針爲Transaction* 故調用的是Transaction::logTransaction(),此時BuyTransaction還沒被構造出來。
構造函數:base::base-->derive::derive
析構函數:base::~base-->derive::~derive
用於鏈式賦值
推薦作法:
Widget& Widget::operator=(Widget rhs) { swap(rhs); //成員函數,進行交換 return *this; }
(1)、確保當對象進行自我賦值時operator=有良好的行爲。包括考慮「來源對象」和「目標對象」的地址(是否爲同一個)、精心周到的語句順序、以及複製交換;
(2)、當一個函數操做多個對象時,確保即便這些對象爲同一個對象,其行爲仍然正確。
(1)、Copying函數應該確保複製「對象內的全部成員變量」及「全部base class」成分;
(2)、不要用某個copying函數實現另外一個copying函數。應該將共同的代碼放進第三個函數中,並由兩個copying函數共同調用。