標籤:
首先來看一個執行個體
1 #include <iostream> 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<assert.h> 5 using namespace std; 6 class A 7 { 8 public: 9 A(){ cout << "A建構函式" << endl; }10 ~A(){ cout << "A解構函式" << endl; }11 virtual void print(){ cout << "父類的虛函數" << endl; }12 void fun(){ cout << "fun a" << endl; }13 virtual void V_fun(){ cout << "virtual fun a" << endl; }14 };15 class B :virtual public A16 {17 public:18 B(){ cout << "B建構函式" << endl;}19 ~B(){ cout << "B解構函式" << endl;}20 void fun(){ cout << "fun b" << endl; }21 virtual void print(){ cout << "B衍生類別實現父類的純虛函數" << endl; }22 virtual void V_fun(){ cout << "virtual fun b" << endl; }23 };24 class C:virtual public A25 {26 public:27 C(){ cout << "C建構函式" << endl; }28 ~C(){ cout << "C解構函式" << endl; }29 void fun(){ cout << "fun c" << endl; }30 //virtual void print(){ cout << "C衍生類別實現父類的純虛函數" << endl; }31 };32 class D :public B,public C33 {34 public:35 D(){ cout << "D建構函式" << endl; }36 ~D(){ cout << "D解構函式" << endl; }37 };38 int main()39 {40 A *a = new B();41 a->fun();42 a->V_fun();43 a->print();44 getchar();45 return 0;46 }
虛函數:
函式宣告和定義和普通的類成員函數一樣,只是在傳回值之前加入了關鍵字“virtual”聲明為虛函數。而虛函數是實現多態的重要手段,意思是只有對虛函數的調用才能動態決定調用哪一個函數,這是相對於普通成員函數而言的,普通的成員函數在編譯階段就能確定調用哪一個函數。
基類A有兩個成員函數fn和v_fn,衍生類別B繼承自基類A,同樣實現了兩個函數,然後在main函數中用A的指標指向B的執行個體(向上轉型,也是實現多態的必要手段),然後分別調用fn和v_fn函數。結果是“fn in A"和"virtual fn in B"。這是因為fn是普通成員函數,它是通過類A的指標調用的,所以在編譯的時候就確定了調用A的fn函數。而v_fn是虛函數,編譯時間不能確定,而是在運行時再通過一些機制來調用指標所指向的執行個體(B的執行個體)中的v_fn函數。假如衍生類別B中沒有實現(完全一樣,不是重載)v_fn這個函數,那麼依然會調用基類類A中的v_fn;如果它實現了,就可以說衍生類別B覆蓋了基類A中的v_fn這個虛函數。這就是虛函數的表現和使用,只有通過虛函數,才能實現物件導向語言中的多態性。
虛繼承:
為瞭解決從不同途徑繼承來的同名的資料成員在記憶體中有不同的拷貝造成資料不一致問題,將共同基類設定為虛基類。這時從不同的路徑繼承過來的同名資料成員在記憶體中就只有一個拷貝,同一個函數名也只有一個映射。這樣不僅就解決了二義性問題,也節省了記憶體,避免了資料不一致的問題。
class 衍生類別名:virtual 繼承方式 基類名
virtual是關鍵字,聲明該基類為衍生類別的虛基類。
在多繼承情況下,虛基類關鍵字的作用範圍和繼承方式關鍵字相同,只對緊跟其後的基類起作用。
聲明了虛基類之後,虛基類在進一步派生過程中始終和衍生類別一起,維護同一個基類子物件的拷貝。
文法:
class 衍生類別: virtual 基類1,virtual 基類2,...,virtual 基類n
{
...//衍生類別成員聲明
};
執行順序
首先執行虛基類的建構函式,多個虛基類的建構函式按照被繼承的順序構造;
執行基類的建構函式,多個基類的建構函式按照被繼承的順序構造;
執行成員對象的建構函式,多個成員對象的建構函式按照申明的順序構造;
執行衍生類別自己的建構函式;
析構以與構造相反的順序執行;
解決了二義性問題,也節省了記憶體,避免了資料不一致的問題。
C++虛函數解析:看陳大神的專欄吧http://blog.csdn.net/haoel/article/details/1948051/
C++之虛函數和虛繼承