Effective C++ Item 7 为多态基类声明virtual析构函数

本文为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其实是一样道理。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值