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

来源:互联网 发布:js push 数组 编辑:程序博客网 时间:2024/05/21 21:44

总结:1.带有多态性质的基类,应该将其析构函数声明为virtual,如果class带有任何虚函数,他就应该有一个virtual的析构函数。

因为如果一个基类的指针指向派生类的对象,而这个基类的析构函数不是虚函数的话,那么在销毁这个指针的时候,派生类对对象中的派生类成份没有被销毁,这样会造成诡异的局部销毁,从而形成资源泄露。

首先来看代码如下:

class Base{public:Base(){ cout << "Base::构造函数" << endl; }    ~Base(){ cout << "Base::析构函数" << endl; } void fun() { cout << "Base::1" << endl; }};class Dervice :public Base{public:Dervice(){ cout << "Dervice::构造函数" << endl; }~Dervice(){ cout << "Dervice::析构函数" << endl; }void fun(){cout << "Dervice::1" << endl;}};void test(){Base *p = new Dervice;delete p;}int main(){test();system("pause");return 0;}

注意在这里只调用了基类的析构函数,而派生类的析构函数没有调用。(附加:基类指针指向派生类是可以的(会有隐式的类型转换吧),但是如果没有多态发生的话,通过基类指针只能访问基类中的成员,因为他无妨访问到派生类的成员,但是如果是派生类的指针指向基类的对象,这是不行的,因为无法把一个基类转换为派生类)

**.如果给基类的析构函数加上virtual这个时候就可以正常的释放派生类部分了

只需要将上述基类中的析构函数声明为虚析构函数,就可以了

  virtual ~Base(){ cout << "Base::析构函数" << endl; }

为什么声明虚析构函数就可以了呢?因为如果不是虚函数的话,不会产生动态联编(不知道动态联编的可以去我博客的多态中看)所以编译器在调用析构函数的时候根据指针的类型进行析构函数调用了,但是如果声明为虚函数的话,这个时候就会产生动态联编,在调用析构函数的时候,编译器根据所传过来的对象,从而先调用派生类的析构函数,然后在调用基类的析构函数了。

2.如果class不含虚函数的话,通常表示他并不意图做一个基类(被继承),所以当一个类不作为基类的时候,令其析构函数为虚函数是个不好的做法,这样会增加类对象的大小(多一个vptr指针,指向vtbl函数指针数组),注意声明为虚析构函数的条件和情况,自己立理解一下。

3.不要随便继承没有虚析构函数的类,因为这样不经意间就会造成派生类对象未被释放,造成资源泄露

4.如果你想使用抽象类作为基类,最好将抽象类的将抽象类的析构函数声明为纯虚析构函数,但是一定记得定义抽象类的析构函数。

class Abstract{public:virtual ~Abstract() = 0;};Abstract::~Abstract(){cout << "Abstract::析构函数" << endl;}
因为在释放对象的 时候在派生类的虚析构函数先被调用,然后再派生类的析构函数中创建基类的析构函数,即使是抽象类,编译器也要调用他的析构函数,所以为了保证不在链接期间发生错误,最好给出抽象类析构函数的定义。

5.构造函数不能定义为虚函数!为什么呢?

说一条我自己的理解吧,因为类中有虚函数,意味着就有vptr指针,然而vptr指针的初始化(使其指向虚表)需要构造函数来完成,这是矛盾的,相当于一个死循环,所以构造函数函数不能是虚函数。具体还有其他的原因,可以查阅相关资料了解。

阅读全文
1 0
原创粉丝点击