做者: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; }