做者:LogM數據庫
本文原載於 https://segmentfault.com/u/logm/articles,不容許轉載~segmentfault
//你覺得你寫了個沒有代碼的空類 class Empty{}; // 實際上,C++自動生成了不少函數 class Empty{ public: Empty() {...} //默認構造函數 Empty(const Empty& rhs) {...} //拷貝構造函數 ~Empty() {...} //析構函數 Empty& operator=(const Empty& rhs) {...} //賦值函數 };
//把拷貝構造函數和賦值函數聲明爲private類型,防止被使用 class Empty { public: ... private: ... Empty(const Empty&); Empty& operator=(const Empty& rhs); };
//一個多態的場景 class TimeKeeper { //計時器(基類) public: TimeKeeper(); virtual ~TimeKeeper(); ... }; class AtomicClock: public TimeKeeper {...} //原子鐘 class WristWatch: public TimeKeeper {...} //腕錶 //每每這麼使用多態特性 TimeKeeper* ptk = getTimeKeeper(); ... delete ptk;
上面是使用多態的一個場景,當delete ptk
時,由於ptk
是TimeKeeper
類型,若是基類析構函數不是virtual
,那麼ptk
的析構時只調用基類析構函數,析構不正確;使用virtual ~TimeKeeper();
保證ptk
析構時調用正確的子類析構函數函數
若是一個類帶有virtual函數,說明這個類有可能用於多態,那麼就應該有virtual析構函數。不要對non-virtual析構函數的類使用多態特性,包括string、vector在內的STL容器。this
帶有virtual函數的類會生成vtbl (virtual table)用於在運行期間肯定具體調用哪一個函數,由vptr (virtual table pointer)指向,佔用空間。胡亂聲明virtual會增長體積。code
//管理數據庫鏈接的典型場景 //若是這麼寫,析構函數有可能拋出異常 class DBConn { public: ... ~DBConn() { db.close(); } private: DBConnection db; } //在析構函數內捕捉異常,不要讓析構函數的異常拋出 class DBConn { public: ... ~DBConn() { try { db.close(); } catch (...) { ... } } private: DBConnection db; }
int x, y, z; x = y = z = 1; //連續賦值 int& operator=(const int& rhs) { ... return *this; //返回左側對象的引用 }
//下面代碼,若是出現自我賦值,則出錯 Widget& Widget::operator=(const Widget& rhs) { delete elem; elem = new Bitmap(*rhs.elem); return *this; } //方法1 Widget& Widget::operator=(const Widget& rhs) { if (this == &rhs) { return *this; } delete elem; elem = new Bitmap(*rhs.elem); return *this; } //方法2 Widget& Widget::operator=(const Widget& rhs) { Bitmap* pOrig = elem; elem = new Bitmap(*rhs.elem); delete pOrig; return *this; }