C++之虛函數和多態
干貨較多-需要自己深思理解:
C++支持兩種多態性:
1.編譯時多態性(靜態綁定-早綁定)
在程序編譯階段即可以確定下來的多態性
通過使用 重載機制(重載函數)實現
(模板)http://blog.csdn.net/my_business/article/details/12194691
2.運行時多態性(動態綁定-晚綁定)
必須等到程序運行時才能確定的多態性
要通過 虛函數 來實現
http://blog.csdn.net/zp752963831/article/details/46635885
第一個父類中 把某個函數 定義成虛函數 ,那么在他的子類中 無論是否加 virtual 都是 虛函數。
例子:
class Base { public: virtual void fun(int i) { OutputDebugString(_T("Base::fun(int i)")); } }; class BaseA :public Base { public: virtual void fun(int i) { OutputDebugString(_T("BaseA::fun(int i)")); } };
其中BaseB 的fun函數 加與不加virtual函數都無所謂,其都是虛函數
但是如果他繼續作為基類,并且要用到多態,則其應該加一個virtual
虛函數的訪問權限:
派生類中所定義的虛函數的訪問權限 不會影響對它的晚綁定
(即:只有在第一個父類中定義的public,private或protect才對 虛函數的訪問 有控制功能)
晚綁定 和 實例化對象 的 class 中函數的訪問權限有關
class base { public: base():strBase(_T("base")) { log(); } virtual void log() { MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK); } public: param strBase; param* pStr; }; class child : public base { public: child() { } /*child(const child& other) { pStr = new param(_T("child2")); }*/
pritave:
virtual void log() { MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK); } public: };
int main()
{
base * pBase = new child();
pBase->log();//ok
child* pChild = static_cast<child*> pBase;
pChild->log();//error
}
在成員函數中調用虛函數:
在一個基類或派生類的虛或非虛成員函數中可以直接調
用該類體系的虛函數或非虛函數
class base { public: base() { log(); } void go() { log(); } virtual void log() { MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK); } }; class child : public base { public: child() { } void go() { log(); } private: virtual void log() { MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK); } public: }; int main() { base * pBase = new child(); pBase->go();//ok 調用父類的go,內部調用子類的log函數。 child* pChild = static_cast<child*>(pBase); pChild->go(); //go 內部直接調用自己的 }
在構造/析構函數中調用虛函數:
在構造函數或析構函數中調用虛函數時,采用的是早綁定。
也就是虛函數機制在構造函數中不工作。
class base { public: base() { log(); } void go() { log(); } virtual void log() { MessageBox(::GetTopWindow(NULL), _T("base"), _T("base"), MB_OK); } }; class child : public base { public: child() { log(); } void go() { log(); } private: virtual void log() { MessageBox(::GetTopWindow(NULL), _T("child"), _T("child"), MB_OK); } }; int main() { base * pBase = new child();//構造父類時,父類構造調用自己的 // log ,子類構造,則用子類的log函數。 }
虛函數和缺省實參:
運行的函數是派生來的函數,但使用的缺省實參是父類里的缺省實參
即:虛函數的缺省實參不支持晚綁定。
class base { public: base() { } virtual void log(int paramI = 1) { SStringT str = paramI; OutputDebugString(str); } }; class child : public base { public: child() { } virtual void log(int paramI = 2) { SStringT str = paramI; OutputDebugString(str); } }; int main() { base * pBase = new child(); pBase->log();// 輸出 1 child* pChild = static_cast<child*>(pBase); pChild->log(); //輸出2 }
純虛函數:
定義:純虛函數是在基類中聲明的虛函數,它在基類中沒有定義,但要求任何派生類都要定義自己的實現方法。
在基類中實現純虛函數的方法是在函數原型后加“ =0”:virtual void funtion1()=0
*引入原因:
1)為了方便使用多態特性,我們常常需要在基類中定義虛擬函數。
2)在很多情況下,基類本身生成對象是不合情理的。
3)實現接口
引入了純虛函數的概念,將函數定義為純虛函數(方法:virtual ReturnType Function()= 0;),則編譯器要
求在派生類中必須予以重載以實現多態性。同時含有純虛擬函數的類稱為抽象類,它不能生成對象。
1
覆蓋:
在c++中,派生類繼承了基類的全部特征,但有時為了更加準確地描述客觀世界的對象,需要對從基類繼承來的接口函數進行修改:
這可以通過在派生類中定義一個與基類同名,而返回值,參數類型,順序或個數都可同可不同的函數,
這樣,通過派生類對象調用該同類型的函數時,調用的是派生類中定義的函數。也就是說,
派生類修改了從基類繼承來的接口行為,也可稱為派生類的函數覆蓋了基類中的同名函數。
重載:重載類成員函數與覆蓋有點類似:相同的方法(函數名)完成不同的行為
覆蓋和重載的 區別:
1.重載是與被重載函數同名,而參數不同(類型、順序或者數量,至少三者之一不同),返回值可同可不同的另一個函數。
2.重載函數必須在同一個類中或不屬于類成員的普通函數之間,不能分布在基類與派生類中。
3.覆蓋是,在基類與派生類中出現的標示符同名的情況。
注:
1.虛函數是一組特殊的覆蓋函數,同組虛函數間要求函數名、返回值、參數類型、數量、順序都相同。
通過對象名調用虛函數時,與調用覆蓋函數的規則一樣-----采用早綁定。
通過對象的指針或引用調用虛函數時采用晚綁定,調用的是指針實際指向,或實際引用的對象對應的類中定義的虛函數
2.如果類外的兩個同名函數,或同類中兩個同名的成員函數參數相同,但返回值不同,編譯器不認為是重載,而認為它們具有二義性,會給出錯誤提示。
3.如果一組虛函數中,兩個虛函數僅返回值不同,但其參數和名字都相同,編譯器也認為出錯。
三者比較表格:
*=======================================================================================*
|函數名 |返回值 |參數 |綁定時間 |適用范圍 |
*---------------+---------------+---------------+-----------------------+---------------*
|虛函數 |同 |同 |晚綁定(指針/引用調用)|基類與派生 |
| | | |早綁定(對象名調用) |類之間 |
*---------------+---------------+---------------+-----------------------+---------------*
|重載函數 |可同可不同 |必須不同 |早綁定 |類外函數或同 |
| | | | |一類中的函數 |
*---------------+---------------+---------------+-----------------------+---------------*
|覆蓋函數 |可同可不同 |可同可不同 |早綁定(支配規則) |基類與派生類 |
| | | | |之間 |
*=======================================================================================*
浙公網安備 33010602011771號