1:virtual關鍵字主要有什么作用
c++中的函數調用默認不適用動態綁定,要觸發動態綁定,必須滿足兩個條件:第一指定為虛函數; 第二通過基類類型的引用或指針調用。
2:哪些情況下可以使用virtual關鍵字呢
virtual可用來定義類函數和應用到虛繼承中
注意:有元函數、構造函數、static靜態函數不能用virtual關鍵字修飾。普通成員函數和析構函數可以用virtual關鍵字修飾。
舉一個例子:
1 #include "stdafx.h" 2 #include<stdlib.h> 3 #include<iostream> 4 using namespace std; 5 6 class GrandFather 7 { 8 public: 9 GrandFather() {} 10 virtual void fun() 11 { 12 cout << "GrandFather call function" << endl; 13 } 14 }; 15 16 class Father:public GrandFather 17 { 18 public: 19 Father() {} 20 void fun() 21 { 22 cout << "Father call function"<< endl; 23 } 24 }; 25 26 class Son : public Father 27 { 28 public: 29 Son() {} 30 void fun() 31 { 32 cout << "Son call function" << endl; 33 } 34 }; 35 36 void Print( GrandFather* father ) 37 { 38 father->fun(); 39 } 40 41 int main(int argc, _TCHAR* argv[]) 42 { 43 Father* pfather = new Son; 44 pfather->fun(); 45 46 GrandFather* grandfather = new Father; 47 Print(grandfather); 48 49 return 0; 50 }
3:virtual的繼承性
只要虛基類定義了virtual,繼承類的該函數也就有virtual屬性。
即GrandFather Father Son同時定義了virtual void fun() 與 GrandFather 一個定義virtual void fun效果是一樣的。
4:虛析構函數
1 #include "stdafx.h" 2 #include<stdlib.h> 3 #include<iostream> 4 using namespace std; 5 6 class GrandFather 7 { 8 public: 9 GrandFather() {} 10 virtual void fun() 11 { 12 cout << "GrandFather call function" << endl; 13 } 14 ~GrandFather() 15 { 16 cout << "GrandFather dstruction " << endl; 17 } 18 }; 19 20 class Father:public GrandFather 21 { 22 public: 23 Father() {} 24 void fun() 25 { 26 cout << "Father call function"<< endl; 27 } 28 ~Father() 29 { 30 cout << " Father destruction " << endl; 31 } 32 }; 33 34 class Son : public Father 35 { 36 public: 37 Son() { cout << "son hello" << endl; } 38 void fun() 39 { 40 cout << "Son call function" << endl; 41 } 42 ~Son() 43 { 44 cout << " Son destruction " << endl; 45 } 46 }; 47 48 void Print( GrandFather* father ) 49 { 50 father->fun(); 51 } 52 53 int main(int argc, _TCHAR* argv[]) 54 { 55 //Father* pfather = new Son; 56 //pfather->fun(); 57 58 //GrandFather* grandfather = new Father; 59 //Print(grandfather); 60 61 Father* father = new Son; 62 delete father; 63 return 0; 64 }
運行結果為:
我們發現執行了Son的構造函數,沒執行Son的析構函數,故把GrandFather的析構函數設置為virtual,如下例:
1 #include "stdafx.h" 2 #include<stdlib.h> 3 #include<iostream> 4 using namespace std; 5 6 class GrandFather 7 { 8 public: 9 GrandFather() {} 10 virtual void fun() 11 { 12 cout << "GrandFather call function" << endl; 13 } 14 virtual ~GrandFather() 15 { 16 cout << "GrandFather dstruction " << endl; 17 } 18 }; 19 20 class Father:public GrandFather 21 { 22 public: 23 Father() {} 24 void fun() 25 { 26 cout << "Father call function"<< endl; 27 } 28 ~Father() 29 { 30 cout << " Father destruction " << endl; 31 } 32 }; 33 34 class Son : public Father 35 { 36 public: 37 Son() { cout << "son hello" << endl; } 38 void fun() 39 { 40 cout << "Son call function" << endl; 41 } 42 ~Son() 43 { 44 cout << " Son destruction " << endl; 45 } 46 }; 47 48 void Print( GrandFather* father ) 49 { 50 father->fun(); 51 } 52 53 int main(int argc, _TCHAR* argv[]) 54 { 55 //Father* pfather = new Son; 56 //pfather->fun(); 57 58 //GrandFather* grandfather = new Father; 59 //Print(grandfather); 60 61 Father* father = new Son; 62 delete father; 63 return 0; 64 }
5:純虛函數
純虛函數的定義如下:
class CVirtual
{
public:
CVirtual() {}
virtual void fun() = 0
{
cout << " CVirtual call function " << endl;
}
virtual ~CVirtual()
{
cout << " CVirtual destruction " << endl;
}
};
純虛函數為后代類提供可覆蓋的接口,但這個類中的版本決不會調用。
含有(或繼續)一個或多個純虛函數的類是抽象基類,抽象基類不能實例化!
繼承類只有重寫這個接口才能被實例化.
這也許會讓人聯想到函數的重載,但是我們一比較就會發現兩者是完全不同的。
1):重載的幾個函數必須在同一個類中。而覆蓋的函數必須在有繼承關系的不同的類中。
2):覆蓋的幾個函數必須函數名、參數、返回值都相同。而重載的函數必須函數名相同,參數不同。參數不同的目的就是為了在函數調用的時候編譯器能夠通過參數來判斷程序是在調用哪個函數。這也很自然的解釋了為什么函數不能通過返回值類重載,因為程序在調用函數時很有可能不關心返回值的,編譯器就無法從代碼中看出程序在調用哪個函數了。
3):覆蓋的函數前必須加關鍵字virtual;重載和virtual沒有任何瓜葛,加不加都不影響重載的運作。