多态的實作原理:
首先介紹下函數重寫 重定義 重載的差別;
函數重寫:
發生在父類和子類之間,子類将父類中的同名函數進行了覆寫,如果在函數前面含有virtual那麼就是重寫,如果沒有就成了覆寫,子類的同名函數将會覆寫(隐藏)父類的同名函數,如果想調用的話,那麼就要使用::作用域運算符
函數重載:
函數重載發生在同類之間,平等關系。在不同的類對函數看似重載的操作是不成立的
多态理論基礎:
靜态聯編:
是程式的比對,連接配接在編譯階段實作,也成為早起比對,重載使用的就是靜态聯編
動态聯編譯:
是指程式聯編推遲到運作時進行,又成為遲綁定
在編譯階段,編譯器自動根據指針的類型判斷是執行的父類對象還是子類對象:出于程式安全的角度講,編譯器認為父類指針指向父類對象,子類指針指向子類對象。這就是靜态聯編的結果
(一)談談你對多态的了解?
答:
1. 多态的實作效果,同樣的調用語句有不同的表現形态:
2. 多态實作有三個條件?
有繼承,有虛函數重寫,有父類指針指向子類對象:
3. Virtual關鍵字告訴編譯器這個函數支援多态,不要根據指針的類型進行調用,而是根據指針所指向的具體的對象,進行函數調用
4. 理論基礎:
動态聯編PK靜态聯編,根據實際的對象的類型來判斷重寫函數的調用
5. 多态的重要意義:
設計模式的基礎,是代碼架構的基石
(二)是否每個類的成員函數都聲明為虛函數,為什麼??
答.可以聲明為虛函數,但是在在定義對象的時候,會生成一個虛函數表,而虛函數在調用的時候是通過尋址實作的,這回影響代碼的執行效率
(三)構造函數中調用虛函數能實作多态嗎?
答.不可以,因為多态的vptr指針是分布初始化的,在子類進行初始化的時候先調用父類的構造函數,這時候子類的父類的Vptr指針都是指向父類的,是以産生不了多态。
(四)為什麼要定義虛析構函數?
答.因為virtual可以指引delete運算符正确析構動态對象
是這樣的,當發生多态的時候,基類指針指向派生類,當釋放記憶體的時候,編譯器根據指針類型去調用相應的函數,由于是基類指針,那麼隻會去調用基類對象的析構
函數,進而導緻發生多态的子類對象的析構函數不能正常執行,但是當聲明為虛析構的時候就能正常使用了,父類析構函數virtual,子類進行重寫,那麼就可以正常的進行析構了。
(五)重點:
就是基類指針指向父類對象還是子類對象???我們在分析的時候是這麼分析的,如果基類指針指向父類對象,那麼就去調用父類的對象;如果指向子類對象,就去調用子類對象。
靜态聯編:是編譯根據指針類型進行對象的确定; 動态聯編譯是根據,指針指向的對象進行函數調用,(要含有虛函數,如果沒有虛函數是不是要報錯(是以産生了dynamic_cast< >這個東東進行運作時類型檢查))
但是實際情況是這樣的,編譯器壓根就不是這麼做的。而是根據傳遞來的是什麼對象,然後看此函數是否是虛函數,如果是虛函數,就去找這個對象對應的虛函數表,然後調用相應的函數。
實作了重載或重寫的函數,如果想在子類中調用父類的函數,那麼可以使用(類名::函數名 ) 的方式來通路父類中的函數
#include<iostream>
using namespace std;
class AA{
public:
int add(int a,int b){
return a + b;
}
virtual int sub(int a,int b){
return a - b;
}
};
class BB :public AA{
public:
int add(int a, int b){
return a + b +10;
}
virtual int sub(int a, int b){
return a - b -10;
}
};
void main(){
int a = 100, b = 100;
BB bb;
AA aa;
int c = aa.add(a, b);//200
cout << c << endl;
c = bb.add(a, b);//210
cout << c << endl;
c = bb.AA::add(a, b);//200
cout << c << endl;
c = bb.sub(a, b);//-10
cout << c << endl;
c = bb.AA::sub(a, b);//0
cout << c << endl;
system("pause");
}