虛函數的定義很簡單, 只要在成員函數原型前加上一個virtual 關鍵字即可. 如果一個父類被宣告為virtual函數, 其所有子類 (含子類的子類) 會保持virtual 特性. 一旦一個函數被宣告為虛函數, 不管繼承幾次, virtual特性將維持. 即使在子類沒使用virtual 關鍵字, 其仍是Virtual 函數.
子類可根據需求對Virtual函數重新定義, 重新定義的挌式有一定要求:
Ps. 友元函數不能是虛函數, 因為友元函數不是類成員. 但虛函數可以是另一個類的友元函數.
指針訪問
使用指針訪問虛函數, 與指針類型無關, 編譯器會根據指針所指類型來實現動態聯編.
引用訪問
使用引用訪問虛函數與使用指針訪問虛函數類似, 不同的是引用已經聲明, 不能修改. 但這在一定程度上提高了代碼的安全性, 特別體現在函數參數的傳遞. 可以將引用視為一種 "受限制的指針", 請參考如下範例:
範例代碼 Base.h:
範例代碼 example_ch11.h:
結果:
由如上代碼得知, 引用訪問虛函數同樣與引用類型無關, 只取決於引用初始化的對象.
類內訪問
編譯器對於使用類對像名進行的虛函數調用是使用靜態聯編, 而且使用諸如 "類名::虛函數" 等使用了作用域運算符亦使用靜態聯編. 此時具體調用哪個函數取決於類名. 如下範例 "void call_base_1()" 中對虛函數的調用是使用動態聯編, 關鍵在於 this 指針的應用.
範例代碼 Base1105.h:
範例代碼 example_ch11.cpp:
結果:
在構造函數或解構函數中訪問
構造函數和解構函數是特殊的成員函數, 在其中訪問虛函數時, C++ 採用靜態聯編. 請參考如下範例:
範例代碼 Base.h:
上述代碼定義創建類Child時, 輸出訊息會是"Hello, child", 換言之在Child的構造函數中, 不論是用disp() 還是 this->disp()來調用, 編譯器都會將之解釋為 Child::disp(), 此時若想在構造函數調用Base類的disp函數, 必須使用作用域運算符, 即Base::disp() 型式.
子類可根據需求對Virtual函數重新定義, 重新定義的挌式有一定要求:
Ps. 友元函數不能是虛函數, 因為友元函數不是類成員. 但虛函數可以是另一個類的友元函數.
指針訪問
使用指針訪問虛函數, 與指針類型無關, 編譯器會根據指針所指類型來實現動態聯編.
引用訪問
使用引用訪問虛函數與使用指針訪問虛函數類似, 不同的是引用已經聲明, 不能修改. 但這在一定程度上提高了代碼的安全性, 特別體現在函數參數的傳遞. 可以將引用視為一種 "受限制的指針", 請參考如下範例:
範例代碼 Base.h:
- #ifndef _BASE
- #define _BASE
- class Base{
- public:
- virtual void disp(){
- cout << "Hello, Base " <
- }
- };
- class Child:public Base{
- public:
- void disp(){
- cout << "Hello, Child " << endl;
- }
- };
- #endif
範例代碼 example_ch11.h:
- ...(以上省略)...
- void example1104(){
- cout << "@ 使用引用訪問Virtual函數 (P273)" << endl;
- Base obj_Base;
- Child obj_Child;
- cout << "Base& rBase1 = obj_Base;" << endl;
- Base& rBase1 = obj_Base;
- rBase1.disp();
- cout << "Base& rBase2 = obj_Child;" << endl;
- Base& rBase2 = obj_Child;
- rBase2.disp();
- }
- ...(以下省略)...
結果:
由如上代碼得知, 引用訪問虛函數同樣與引用類型無關, 只取決於引用初始化的對象.
類內訪問
編譯器對於使用類對像名進行的虛函數調用是使用靜態聯編, 而且使用諸如 "類名::虛函數" 等使用了作用域運算符亦使用靜態聯編. 此時具體調用哪個函數取決於類名. 如下範例 "void call_base_1()" 中對虛函數的調用是使用動態聯編, 關鍵在於 this 指針的應用.
範例代碼 Base1105.h:
- #ifndef _BASE_1105
- #define _BASE_1105
- class Base1105{
- public:
- virtual void disp(){
- cout << "Hello, Base" << endl;
- }
- void call_base_1(){
- cout << " this->disp();" << endl;
- this->disp();
- }
- void call_base_2(){
- cout << " Base1105::disp();" << endl;
- Base1105::disp();
- }
- };
- class Child1105:public Base1105{
- public:
- void disp(){
- cout << "Hello, Child" << endl;
- }
- void call_child_1(){
- disp();
- }
- };
- #endif
範例代碼 example_ch11.cpp:
- ...(以上省略)...
- void example1105(){
- showMessage("@ 類內成員函數訪問Virtual函數 (P274)");
- Base1105 obj_Base;
- Child1105 obj_Child;
- cout << " obj_Base.call_base_1();" << endl;
- obj_Base.call_base_1();
- cout << " obj_Child.call_child_1();" << endl;
- obj_Child.call_child_1();
- cout << " Base1105* pBase=&obj_Base;" << endl;
- Base1105* pBase=&obj_Base;
- cout << " pBase->call_base_1();" << endl;
- pBase->call_base_1();
- cout << " pBase->call_base_2();" << endl;
- pBase->call_base_2();
- cout << " pBase = &obj_Child;" << endl;
- pBase = &obj_Child;
- cout << " pBase->call_base_1();" << endl;
- pBase->call_base_1();
- cout << " pBase->call_base_2();" << endl;
- pBase->call_base_2();
- }
- ...(以下省略)...
結果:
在構造函數或解構函數中訪問
構造函數和解構函數是特殊的成員函數, 在其中訪問虛函數時, C++ 採用靜態聯編. 請參考如下範例:
範例代碼 Base.h:
- class Base{
- public:
- virtual void disp(){
- cout << "Hello, base" << endl;
- }
- };
- class Child:public Base{
- public:
- Child(){
- disp();
- }
- disp(){
- cout << "Hello, child" << endl;
- }
- };
上述代碼定義創建類Child時, 輸出訊息會是"Hello, child", 換言之在Child的構造函數中, 不論是用disp() 還是 this->disp()來調用, 編譯器都會將之解釋為 Child::disp(), 此時若想在構造函數調用Base類的disp函數, 必須使用作用域運算符, 即Base::disp() 型式.
This message was edited 5 times. Last update was at 27/01/2010 15:10:25
沒有留言:
張貼留言