您的位置:首页 > 编程语言 > C语言/C++

Effective C++:条款07:为多态基类声明virtual析构函数

2014-06-07 20:56 387 查看
(一)

假设有以下继承关系:

class TimeKeeper {
public:
TimeKeeper();
~TimeKeeper();           //<span style="color:#ff0000;">non_virtual!!!!!!!
</span>};
class AtomicClock : public TimeKeeper {...};
class WaterClock : public TimeKeeper{...};
class WristWatch : public TimeKeeper{...};

factory(工厂)函数:返回一个base class指针,指向新生成之derived class对象!

TimeKeeper* getTimeKeeper();
TimeKeeper* ptk = getTimeKeeper();
AtomicClock at;
ptk = &at;
...
delete ptk;

ptk指向一个AtomicClock对象!当执行delete ptk;的时候,该derived class对象的base class成分会被删除,但是derived成分却没有被销毁!这是因为derived class的析构函数没有被调用!这就造成了一个诡异的“局部销毁”对象!所以就会形成资源泄漏、败坏数据结构。

解决方法:给base class的析构函数声明为:virtual。这样就解决问题了!

经验:任何class只要带有virtual函数都几乎确定应该也有一个virtual析构函数。

(二)如果一个class不含virtual函数,通常表示它并不意图被用做一个base class。当class不企图被当作base class的时候!不要令其析构函数为:virtual。

因为那样的话,当申请一个该类的对象的时候,伴随着该类会有一个vptr的出现,指向由函数指针构成的一个数组(vtbl),这是C++中虚函数的底层实现!这样的话就无意中增加了该类在内存中占有的大小!

比如:

class Point {
public;
Point(int xCorrd, int yCorrd);
~Point();
private:
int x, y;
};

Point p;

如果它的析构函数不是虚函数的话,那么他在内存中占64bits。但是因为虚函数的原因,会有一个vptr伴随着该对象,所以在32位系统中,该对象占96bits。

这样的话该对象不再能够塞入一个64bit缓存器,而C++的Point对象也不再和其他语言内的相同声明有着一样的结构(因为其他语言的对应物并没有vptr),因此也就不再可能把它传递至(或接受自)其他语言所写的函数!除非我们明确补偿vptr,但是那样的话就不再具有移植性!!!

所以:只有当class内含至少一个virtual函数,才把它声明为virtual析构函数!

(三)

string是的析构函数不是虚函数,同样的STL里的容器也是。看下面代码:

class SpecialString : public string {
...;
};
SpecialString* pss = new SpecialString("Impending Doom");
string* ps;
...
ps = pss;
...
delete ps;

由于string的析构函数不是虚函数,所以跟本文第一点一样!造成了一个诡异的“局部销毁”对象! 现实中*ps的SPecialString资源会泄露,因为string的析构函数不是虚函数!所以SPecialString的析构函数没有被调用!

(四)

当你希望一个class不能被实体化的时候!意思就是我们希望有个抽象class的时候!

方法:为你希望它成为抽象的那个class声明一个pure virtual析构函数。像下面这样:

class AWOV {
public:
virtual ~AWOV() = 0;
};

AWOV::~AWOV() {}    //定义!不定义的话,当AWOV派生类对象被析构的时候,连接器会报错!


请记住:

(1)polymorphic(带多态性质的)base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它也应该拥有一个virtual析构函数!

(2)Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性!就不该声明virtual析构函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: