基类的析构函数为什么要设成虚函数 - so true - BlogJava

来源:百度文库 编辑:神马文学网 时间:2024/06/03 10:08:25

基类的析构函数为什么要设成虚函数

#include

class A
{
public:
 A(){cout<<"A()\n";}
 ~A(){cout<<"~A()\n";}
 
};

class B : public A
{
public:
 B(){cout<<"B()\n";}
 ~B(){cout<<"~B()\n";}
};

void main()
{
 A * p = new B();
 delete p ;  
}
输出结果:
A()
B()
~A()
============================================================
在基类的析构函数前添加virtual改编后的代码:
#include

class A
{
public:
 A(){cout<<"A()\n";}
 virtual ~A(){cout<<"~A()\n";}
 
};

class B : public A
{
public:
 B(){cout<<"B()\n";}
 ~B(){cout<<"~B()\n";}
};

void main()
{
 A * p = new B();
 delete p ;  
}

输出结果:
A()
B()
~B()
~A()
=================================================================
如果不是在基类的析构函数前添加virtual,而是在子类的析构函数前添加virtual,则编译不会出错,但是运行会出错。如果在此基础上再把“deletep;”这句话给注释了,那依然不会运行出错,不过这就不符合变成规范了,只要是我们自己用new创建的东西,我们就必须在适当的位置显示的调用delete来删除。
=================================================================
如果再添加一个中间类,代码如下:
#include
#include

class A
{
public:
 A(){cout<<"A()\n";}
 virtual ~A(){cout<<"~A()\n";}
};

class B : public A
{
public:
 B(){cout<<"B()\n";}
 virtual ~B(){cout<<"~B()\n";}
};

class C : public B
{
public:
 C(){cout<<"C()\n";}
 ~C(){cout<<"~C()\n";}
};

void main()
{
 A * p = new C();
 delete p ;  
}
输出结果为:
A()
B()
C()
~C()
~B()
~A()
析构函数前添加virtual,必须要在最最根上的基类的析构函数前添加,不能再B类或C类的析构函数前添加,只要A类的析构函数添加了virtual,从A类派生的类都不必在自己的析构函数前添加virtual了。
所以如果没有虚析构函数的话, 那么子类中特有的部分就不会被释放, 造成"经典"的释放一半, 泄露一半的内存泄露.