可以说百分之八十的IT公司在面试的时候都会问你有关虚函数的问题,尤其是析构函数为什么要用虚函数,一句话说白了,就是内存泄露的问题,在公有继承中,基类对派生类对象的操作,只能影响到那些从基类继承下来的成员,如果想要用基类对非继承的成员进行操作,则需将基类的这个函数定义为虚函数。
如下面的例子
class A
{
public:
A(){};
~A(){cout<<"A is destructed"<<endl;};
};
class B :public A
{
public:
B(){};
~B(){cout<<"B is destructed"<<endl;};
};
void main()
{
A* b = new B;
delete b;
}
则最后输出的结果为 A is destructed,
在这个例子的main函数中,我们用了A类的指针去操作B类的对象,而在我们释放掉A类的指针之后,我们调用的析构函数是A类的析构函数,释放的是基类的资源,一般情况下,这样的删除只能删除基类对象,而不能删除子类对象,这样就造成了内存泄露。
因此,我们对上面的例子进行修改如下
class A
{
public:
A(){};
virtual ~A(){cout<<"A is destructed"<<endl;};
};
class B :public A
{
public:
B(){};
~B(){cout<<"B is destructed"<<endl;};
};
void main()
{
A* b = new B;
delete b;
}
则最后的输出结果为
B is destructed
A is destructed
上面的代码中,析构函数被定义为虚函数,用A类的指针去操作B类的对象,释放指针b的过程为,先释放掉继承类的资源,在释放掉基类的资源。
如果不需要基类对派生类或派生类的对象进行操作,则不能将析构函数定义为虚函数,因为这样会增加内存的开销,我们知道,当你定义一个类的时候,编译器会为这个类增加一个虚函数表,里面存放虚函数指针,这样就会增加类的存储空间,只有当一个类为基类的时候,析构函数才定义为虚函数。
我们再来看下面的例子
class A
{
public:
A(){};
void print(){cout<<"A is printing......"<<endl;};
virtual ~A(){cout<<"A is destructed"<<endl;};
};
class B :public A
{
public:
B(){};
void print(){cout<<"B is printing......"<<endl;};
~B(){cout<<"B is destructed"<<endl;};
};
void main()
{
A* b = new B;
b->print();
delete b;
}
则输出的结果为
A is printing......
B is destructed
A is destructed
当我们将类中的函数 print()定义为虚函数的时候,代码如下
class A
{
public:
A(){};
virtual void print(){cout<<"A is printing......"<<endl;};
virtual ~A(){cout<<"A is destructed"<<endl;};
};
class B :public A
{
public:
B(){};
virtual void print(){cout<<"B is printing......"<<endl;};
~B(){cout<<"B is destructed"<<endl;};
};
void main()
{
A* b = new B;
b->print();
delete b;
}
则最后输出的结果为
B is printing......
B is destructed
A is destructed
从而说明如果想要用基类对非继承的成员进行操作,则需将基类的这个函数定义为虚函数。