C++多态的概念及前提条件(最精辟)
原文鏈接
在 C++ 程序中,每一個函數在內存中會分配一段存儲空間,存儲空間的起始地址則為函數的入口地址。例如我們在設計一個程序時都必須為程序設計一個主函數,主函數同樣會在內存中被分配一段存儲空間,這段存儲空間的起始地址就是函數的入口地址
-
前面列舉的所有程序中,函數的入口地址與函數名是在編譯時進行綁定的,我們稱之為編譯期綁定
-
多態的功能則是將函數名動態綁定到函數入口地址,這樣的動態綁定過程稱為運行期綁定。
-
運行期綁定指的是函數名與函數入口地址在程序編譯時無法綁定到一起,只有等運行的時候才確定函數名與哪一個函數入口綁定到一起
那么多態到底有什么用處呢?我們不妨來看個例子。在 windows 操作系統中,我們經常會進行一些關閉操作,比如關閉文件夾、關閉文本文件、關閉播放器窗口等,這些關閉動作對應的 close() 函數假設都繼承自同一個基類,但是每一個類都需要有自己的一些特殊功能,比如清理背景、清除緩存等工作。當執行 close() 函數時,我們當然希望根據當前所操作的窗口類型來決定該執行哪一個 close() 函數,因此運行期綁定就可以派上用場了
- 編譯期綁定是指在程序編譯時就將函數名與函數入口地址綁定到一起,運行期綁定是指在程序運行時才將函數名與函數入口地址綁定到一起,而在運行期綁定的函數我們稱其是多態的。
為了說明虛函數的必要性,我們先來看一個示例程序。
#include<iostream> using namespace std; class base { public:void display(){cout<<"I'm base class!"<<endl;} }; class derived: public base { public:void display(){cout<<"I'm derived class!"<<endl;} }; int main() {base * p;derived test;p = &test;p->display();return 0; }這個例子非常簡單,兩個類,一個是 base 類,一個是 derived 類,二者構成繼承關系,同時在這兩個類中均含有一個 display() 函數,因為函數同名,故在派生類對象中會出現遮蔽現象,即派生類中的 display() 函數會遮蔽基類中的 display() 函數。
在主函數中,定義了一個基類類型的指針 p 和派生類對象 test,之后 p 指針指向派生類對象 test,然后通過指針調用 display() 函數。此程序最終運行結果如下:
I'm base class!從結果來看,這個程序最終調用的 display() 函數是基類的 display () 函數,而非派生類中的 display() 函數。但此程序的本意是先通過基類類型的指針根據所指向對象的類型來自動決定調用基類還是派生類的 display() 函數。為了實現這樣的一種功能,C++ 提供了多態這一機制。
要想形成多態必須具備以下三個條件:
- 必須存在繼承關系;
- 繼承關系中必須有同名的虛函數;
- 存在基類類型的指針或引用,通過該指針或引用調用虛函數。
根據這三個條件,我們將例 1 進行修改,使 display() 函數具有多態特性。修改后程序如例 2 所示。
相對于例 1,例 2 只是在 display() 函數前各添加了一個 virtual 關鍵字。我們對照三個多態的構成條件來分析一下:
- 多態需要繼承關系,derived 類繼承自 base 類,因此 base 類和 derived 類構成繼承關系;
- 多態需要同名的虛函數,base 類和 derived 類中都有 display() 函數,同名滿足,同時通過添加關鍵字 virtual 后,display() 函數成為虛函數;
- 多態需要通過基類類型的指針或引用來調用虛函數,在例 2 中的主函數中,p 即為基類類型指針,并且將該指針指向派生類對象,然后調用 display() 函數。
這段程序最終運行結果如下:
I'm derived class!總結
以上是生活随笔為你收集整理的C++多态的概念及前提条件(最精辟)的全部內容,希望文章能夠幫你解決所遇到的問題。