请说明下列代码的输出,并解释原因。
#include<stdio.h> class A { public: virtual ~A(); }; A::~A() { printf("delete A\n"); } class B : public A { public: ~B(); }; B::~B() { printf("delete B\n"); } int main(int argc, char **argv) { A* pa = new B(); delete pa; }
输出结果:
delete B
delete A
C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。
对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。
C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
子类没有重载任何父类的函数时,虚函数按照其声明顺序放于表中,父类的虚函数在子类的虚函数前面。
如果子类中有虚函数重载了父类的虚函数,覆盖的函数被放到了虚表中原来父类虚函数的位置,没有被覆盖的函数依旧。
Base *b = new Derive(); b->f();
此时,由b所指的内存中的虚函数表的f()的位置已经被Derive::f()函数地址所取代,于是在实际调用发生时,是Derive::f()被调用了。
任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法,所以,这样的程序根本无法编译通过。但在运行时,我们可以通过指针的方式访问虚函数表来达到违反C++语义的行为。
参考:
http://blog.csdn.net/haoel/article/details/1948051/