先帖段代码
class A{ public: virtual void f1(){puts("A");} virtual void f2(){f1();} }; class B:public A{ public : void f1(){puts("B");} void f2(){f1();} }; class C:public A{ public: void f1(){puts("C");} }; int _tmain(int argc, _TCHAR* argv[]) { A a; B b; C c; a.f2(); b.f2(); c.f2(); printf(" "); a.f1(); a.f2(); a=b;//没有效果? a.f1(); a.f2(); printf(" "); class A *pa=NULL; pa=&b; pa->f1(); pa->f2(); pa=&c; pa->f1(); pa->f2(); printf(" "); return 0; }
简单说明下,基类A有两个虚函数,B继承了A同时重载了这两个虚函数,C继承了A但只重载了一个虚函数
a.f2(), b.f2(), c.f2()这三句结果分别为A B C,因为A的虚表中的函数是A::f1() 和A::f2(),而B的虚表中的函数是B::f1() 和B::f2(),C中的虚表中内容是C::f1() 和A::f2(),这个没什么问题。
本段代码难点在接下来的a=b这句,本以为在执行这句赋值语句后a的虚表的内容会发生变化,就是说a.vftable(这是一个指针)会变成b.vftable,但结果a的虚表仍指向原来的内容,指针并未发生改变,这是为什么呢?
在A类中重载A& operator=(A& b) { puts("operator=()"); return b; },发现虽然执行此函数,但a的内容没有因此改变,难道是虚表是不会被赋值运算符改变?
为了验证虚表和普通成员变量不同,我们在A中添加了一个成员变量a,让B中的这个继承而来的变量a和A中的a不同,测试在赋值时A中的a是否因此发生改变,具体修改代码如下
class A{ public: virtual void f1(){puts("A");} virtual void f2(){f1();} A(int n=0):a(n){} protected: int a; }; class B:public A{ public : void f1(){puts("B");} void f2(){f1();} B(int n=5):b(n){//a是A的成员变量,虽然被B继承,但仍不能在初始化列表初始化 a=n+1; } protected: int b; };
这样B中的a默认会为6,而A中的a默认为0,执行a=b发现,a中的a已经变成了6,说明这句赋值后a中的成员变量被修改,但虚表指针没有被修改!!!
至于为什么赋值不影响虚表,这个应该是可以理解的,属于设计时有意为之,虚表和虚函数的存在是为了多态,如果允许其被修改,则会导致失去多态性