1. 虚函数的实现原理 ios
在C++的类内会维护一个虚表,同时还有一个虚指针。能够经过VC 6.0来观看类的虚函数表。 网络
#include <iostream> #include <stdio.h> class A{ public : virtual void f(){ std::cout<<"This is A's f"<<std::endl;}; virtual void g(){ std::cout<<"This is A's g"<<std::endl;}; }; class B : public A{ public: B(){}; void f(){ std::cout<<"This is B's f"<<std::endl;}; }; class C : public A{ public: void g(){ std::cout<<"This is C's g"<<std::endl;}; }; class D : public C,B{ public: void f(){ std::cout<<"This is D's f"<<std::endl;}; void g(){ std::cout<<"This is D's g"<<std::endl;}; }; #define E_ss E::ss() int main() { A a; B b; C c; D d; std::cout<<"A's address is "<<&a<<std::endl; std::cout<<"B's address is "<<&b<<std::endl; std::cout<<"C's address is "<<&c<<std::endl; std::cout<<"D's address is "<<&d<<std::endl; return 0; }
C++的类中第一个变量就是虚指针。其中a类的地址是0x0012ff44,紧接着就是虚指针。而b类的地址为0x0012ff40,因而可知a类内只有虚指针这一个变量。 函数
解决了虚指针的问题,如今正式进入虚函数表。从代码能够看到,A类内定义了两个虚函数 f() 和 g() ,B类继承A类,实现了虚函数 f() ,并无实现 g() , C类正好相反。D类暂时不讨论,她负责解释多重继承产生二义性的问题。 spa
经过VC 6.0的调试能够看到各个虚函数的地址,如图。 指针
能够看到,a类的虚指针里有两个虚函数地址分别为0x004012cd(A::f(void))和0x004011b8(A::g(void))。而b类继承a类,因为b类只实现了虚函数f(),因此b类的虚指针内的B::f(void)是指向b类内实现的虚函数,而g()函数仍是指向A类的A::g(void)函数。C类则与B类相似。 调试
总结下,C++的类是经过一个虚指针(__vfptr)指向一个虚函数表来实现虚函数的功能,从而实现动态的多态。 code
2. 经过子类调用父类”们“方法 继承
依然是刚才那段代码,我在B、C、D类内分别写了test(),来调用父类”们“的方法。 io
#include <iostream> #include <stdio.h> class A{ public : virtual void f(){ std::cout<<"This is A's f"<<std::endl;}; virtual void g(){ std::cout<<"This is A's g"<<std::endl;}; }; class B : virtual public A{ public: void f(){ std::cout<<"This is B's f"<<std::endl;}; void test() { std::cout<<"This is B's test"<<std::endl; A::f(); A::g(); } }; class C : virtual public A{ public: void g(){ std::cout<<"This is C's g"<<std::endl;}; void test() { std::cout<<"This is C's test"<<std::endl; A::f(); A::g(); } }; class D : public C,B{ public: void f(){ std::cout<<"This is D's f"<<std::endl;}; void g(){ std::cout<<"This is D's g"<<std::endl;}; void test() { std::cout<<"This is D's test"<<std::endl; A::f(); A::g(); B::f(); C::g(); } }; int main() { A a; B b; C c; D d; b.test(); c.test(); d.test(); return 0; }
在运行时对继承方式作了修改,经过网络图和结果显示。具体请看下图。 class
总结下,无论怎么继承子类均可以调用父类的方法,可是当子类B、C私有继承类A时,类B、C的子类D则不能调用类A的方法。