参考资料:http://www.programfan.com/article/2782.html
作为通常的原则,如果一个类定义了虚函数,那么它的析构函数就应当是virtual的。因为定义了虚函数则隐含着:这个类会被继承,并且会通过基类的指针指向子类对象,从而得到多态性。”,因此基类的析构函数是否为虚将决定子类的对象是否被析构。
虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。
class A
{
public:
virtual voidfoo() { cout << "A::foo() is called"<< endl;}
};
class B: public A
{
public:
virtual voidfoo() { cout << "B::foo() is called"<< endl;}
};
那么,在使用的时候,我们可以:
A * a = new B(); 父类类型的指针指向子类类型的对象,从而父类调用子类函数
a->foo();
class A
{
public:
virtual voidfoo();
};
class B: public A
{
virtual voidfoo();
};
void bar()
{
A a;
a.foo(); // A::foo()被调用
}
void bar(A * a)
{
a->foo(); //若a指向A的实例,则A的foo被调用,若a指向B的实例,则B的foo被调用。 多态
}
1.3 如何“动态联编”
void bar(A * a)
{
}
会被改写为:
void bar(A * a)
{
}
一个类只有一个VTABLE,所以基类和派生类具有自己的VTABLE(函数指针)。但两者有相同的虚函数排列顺序。同名的虚函数被放在VTABLE表的相同位置。
在创建类实例时,编译器会在类的内存空间生成一个vptr字段,指向该类的VTABLE.
当调用上面的foo函数时,根据A *a=new A 还是 A *a=new B决定调用哪个类的foo函数,从而实现多态。
#include <iostream>
using namespace std;
struct A
{
A(){cout<<"A::()"<<endl;}
virtual ~A(){cout<<"~A()\n";}
};
struct B: public A
{
B(){cout<<"B::()"<<endl;}
~B(){cout<<"~B()\n";}
};
基类声明的虚函数,在派生类中也是虚函数,即使不再使用virtual关键字。
int main()
{
}
如果 A的析构函数不是virtual的,那么此时就不是先调用B的析构函数再调用A的析构函数。
输出:
~A();
如果A的析构函数为virtual,则先~B(),再~A()
输出:
~B();
~A();
类如果会被派生的话,析构函数一般都应该定义为virtual的,主要不是防止内存泄露,而是为了正确的析构。如果是个封闭类(即不再被派生),就不要定义为virtual的。虚函数毕竟耗费较大的。
不用virtual 的几种情况:
声明基类的析构函数为virtual并非总是为了防止memory
overload重载:不同的参数列表,在静态编译的时候已经确定了。
override覆盖/重写:同样的参数列表,实现多态。在执行时动态联编
2.2 纯虚函数
class A
{
public:
};