Effective C++:条款07:为多态基类声明virtual析构函数
2014-06-07 20:56
387 查看
(一)
假设有以下继承关系:
factory(工厂)函数:返回一个base class指针,指向新生成之derived class对象!
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++中虚函数的底层实现!这样的话就无意中增加了该类在内存中占有的大小!
比如:
如果它的析构函数不是虚函数的话,那么他在内存中占64bits。但是因为虚函数的原因,会有一个vptr伴随着该对象,所以在32位系统中,该对象占96bits。
这样的话该对象不再能够塞入一个64bit缓存器,而C++的Point对象也不再和其他语言内的相同声明有着一样的结构(因为其他语言的对应物并没有vptr),因此也就不再可能把它传递至(或接受自)其他语言所写的函数!除非我们明确补偿vptr,但是那样的话就不再具有移植性!!!
所以:只有当class内含至少一个virtual函数,才把它声明为virtual析构函数!
(三)
string是的析构函数不是虚函数,同样的STL里的容器也是。看下面代码:
由于string的析构函数不是虚函数,所以跟本文第一点一样!造成了一个诡异的“局部销毁”对象! 现实中*ps的SPecialString资源会泄露,因为string的析构函数不是虚函数!所以SPecialString的析构函数没有被调用!
(四)
当你希望一个class不能被实体化的时候!意思就是我们希望有个抽象class的时候!
方法:为你希望它成为抽象的那个class声明一个pure virtual析构函数。像下面这样:
请记住:
(1)polymorphic(带多态性质的)base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它也应该拥有一个virtual析构函数!
(2)Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性!就不该声明virtual析构函数。
假设有以下继承关系:
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析构函数。
相关文章推荐
- Effective C++学习笔记 条款07:为多态基类声明virtual析构函数
- effective C++ 读书笔记 条款07 为多态基类声明virtual析构函数
- 读书笔记《Effective C++》条款07:为多态基类声明virtual析构函数
- 读书笔记《Effective c++》 条款07 为多态基类声明virtual析构函数
- effective c++ 条款07(为多态基类声明virtual析构函数)整理
- Effective C++_笔记_条款07_为多态基类声明virtual析构函数
- Effective C++学习笔记 条款07:为多态基类声明virtual析构函数
- 《effective C++》:条款07——为多态基类声明virtual析构函数
- Effective C++ 条款07:为多态基类声明virtual析构函数
- Effective C++--条款07:为多态基类声明virtual析构函数
- Effective C++学习7 条款07:为多态基类声明virtual析构函数
- 《Effective C++》条款07:为多态基类声明virtual析构函数
- 《Effective C++》学习笔记条款07 为多态基类声明virtual析构函数
- [Effective C++]条款07 为多态基类声明virtual析构函数
- 条款07 为多态基类声明virtual析构函数
- Effective c++学习笔记——条款07:为多态基类声明virtual析构函数
- effective c++条款07为多态基类声明为virtual析构函数
- 条款:07 为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数