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的方法。