本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie
经验1:带多态性质的基类应该声明一个virtual 析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual 析构函数
示例:不为带多态性质的基类声明一个virtual析构函数
#include <iostream>
#include <string>
using namespace std;
class TimeKeeper
{
public:
~TimeKeeper(){cout << "TimeKeeper destructor" << endl;}
};
class AtomicClock: public TimeKeeper{
~AtomicClock(){cout << "AtomicClock destructor << endl";}
};
class WaterClock: public TimeKeeper{
~WaterClock(){cout << "WaterClock destructor << endl";}
};
TimeKeeper* getTimeKeeper(string type){
if(type == "AtomicClock") return new AtomicClock();
else return new WaterClock();
}
int main(){
TimeKeeper *tk = getTimeKeeper("AtomicClock");
delete tk;
system("pause");
}
输出:
TimeKeeper destructor
解析:
当derived class 对象经由一个base class 指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义——实际执行时通常发生的是对象的derived成分没被销毁,造成资源泄漏。
纠正:为带多态性质的基类声明一个virtual析构函数
#include <iostream>
#include <string>
using namespace std;
class TimeKeeper
{
public:
virtual ~TimeKeeper(){cout << "TimeKeeper destructor" << endl;} //这里多了个virtual
};
class AtomicClock: public TimeKeeper{
~AtomicClock(){cout << "AtomicClock destructor" << endl;}
};
class WaterClock: public TimeKeeper{
~WaterClock(){cout << "WaterClock destructor << endl";}
};
TimeKeeper* getTimeKeeper(string type){
if(type == "AtomicClock") return new AtomicClock();
else return new WaterClock();
}
int main(){
TimeKeeper *tk = getTimeKeeper("AtomicClock");
delete tk;
system("pause");
}
输出:
AtomicClock destructor
TimeKeeper destructor
经验2:classes的设计目的如果不是作为base classes使用,或不是为了具备多态性,就不该声明virtual 析构函数
示例:
#include <iostream>
#include <string>
using namespace std;
class Point1{
public:
~Point1(){};
private:
int x, y;
};
class Point2{
public:
virtual ~Point2(){};
private:
int x, y;
};
int main(){
Point1 p1;
Point2 p2;
cout << sizeof(p1) << endl
<< sizeof(p2) << endl;
system("pause");
}
输出:
8
12
解析:
p1的size是8:两个int类型分别是4个字节,所以总共是8个字节
p2的size是12:两个int类型分别是4个字节,共8个字节;有一个virtual函数,所以对象要携带一个虚表指针vptr(virtual table pointer),vptr指向一个由函数指针构成的数组,称为vtbl(virtual table),用来在运行期决定哪一个virtual 函数该被调用。具体关于虚表指针的问题可参见陈皓的博客( http://blog.csdn.net/haoel/article/details/1948051 )。由输出结果可见,无端地将所有classes的析构函数声明为virtual,会增加class的对象的存储空间。因此只有当class内含有至少一个virtual函数时,才要将析构函数声明为virtual
经验3:不要企图继承一个标准容器或者其他包含“non-trivial 析构函数”的class,例如string, vector, list, set 等
示例:
#include <iostream>
#include <string>
using namespace std;
class SpecialString: public string{
public:
~SpecialString(){cout << "SpecialString destructor" << endl;}
};
int main(){
SpecialString *pss = new SpecialString();
string *ps = pss;
delete ps;
system("pause");
}
输出:
(空)
解析:
标准string 不含任何virtual函数,delete指向SpecialString类型的指针,只会调用string类的析构函数,不会调用SpecialString的析构函数,现实中*ps的SpecialString资源会泄漏。这跟经验1其实是一样道理。