多態
面向對象三大概念:封裝、繼承、多態;
多態:從某個函數中取得“正確的”行爲,而又不依賴於實際使用的到底是哪一種函數,這就是所謂的多態性。
一個帶有虛函數的類型被稱爲一個多態類型;要在C++裏取得多態性的行爲,被調用的函數必須是虛函數,而對象則必須是通過指針或者引用去操作的;
爲什麼需要多態?
若子類定義和父類中原型相同的函數會發生什麼?
#include <iostream>
using namespace std;
class Parent
{
public:
void print(){
cout<<"Parent:print() do..."<<endl;
}
};
class Child : public Parent
{
public:
void print(){
cout<<"Child:print() do..."<<endl;
}
};
int main(){
//子類和父類中函數同名,父類中同名含默認被 隱藏
Child child;
child.print();
//
Parent *p = NULL;
p = &child;
(*p).print();
//怎麼通過分辨符訪問父類中被隱藏的函數?
child.Parent::print();
system("pause");
return 0;
Child:print() do...
Parent:print() do...
Parent:print() do...
請按任意鍵繼續. . .
父類中被重寫的函數依然會繼承給子類,默認情況下子類中重寫的函數將隱藏父類中的函數,通過作用域分辨符::可訪問到父類中被隱藏的函數;
C/C++是靜態編譯型語言,在編譯時,編譯器自動根據指針的類型判斷指向的是一個什麼的對象。
1、在編譯此函數的時,編譯器不可能知道指針 p 究竟指向了什麼。
2、編譯器沒有理由報錯。
3、編譯器認爲最安全的做法是編譯到父類的print函數,因爲父類和子類肯定都有相同的print函數。
面向對象新需求
編譯器的默認選擇不是我們所想要的;根據實際的對象類型來判斷重寫函數的調用;
若父類指針指向父類對象則代用父類中的函數;
若父類指針指向子類對象則調用子類中的函數;
解決方法:
使用virtual關鍵字對多態進行支持;
使用virtual聲明的函數被重寫後可展現多態特性;
多態條件
要有繼承關係、存在函數重寫(C虛函數)、存在父類指針(父類引用)指向子類對象;
多態理論基礎
靜態聯編和動態聯編
聯編指一個程序模塊、代碼之間互相關聯的過程;
靜態聯編(static binding)是程序匹配、連續在編譯階段實現,即早期匹配,如重載函數使用靜態聯編;
動態聯編指程序聯編推遲到運行時進行,即晚期聯編(遲綁定),如switch語句和if語句是動態聯編;
C++與C相同,是靜態編譯型語言;
編譯時,編譯器自動根據指針的類型判斷指向是一個什麼樣的對象,所以編譯器認爲父類指針指向的父類對象;
程序未運行時,無法判斷父類指針指向的具體對象(父類或子類);
從程序安全角度,編譯器假定父類指針指向父類對象,所以編譯的結果爲調用父類的成員函數,該特性即爲靜態聯編;
Question
怎麼理解多態
多態是同樣的調用語句有多種不同的表現形態;
實現的三個條件:有繼承、有virtual重寫、有父類指針(引用)指向子類對象;
C++實現:
virtual關鍵字告訴編譯器該函數要支持多態;不是根據指針類型判斷調用關係,而是根據指針指向的實際對象類型來判斷調用關係;
根據實際的對象類型來判斷重寫函數的調用;
多態是設計模式的基礎?
函數指針做函數參數是多態實現的基礎?
多態原理?
對重寫、重載理解
函數重載:
必須在同一個類中進行;
子類無法重載父類的函數,父類同名函數將被名稱覆蓋;
重載是在編譯期間根據參數類型和個數決定函數調用;
函數重寫
必須發生在父類與子類之間;
且父類與子類中的函數必須有完全相同的原型;
使用virtual聲明後,能夠產生多態(若不使用virtual,那是重定義);
多態在運行期間根據具體對象的類型決定函數調用;
C++編譯器多態實現原理理解
是否可將每個成員函數夠聲明爲虛函數,爲什麼?