多態:多種形態
舉個例子,你有兩個fun函數,第一個類中fun的功能是打印1,第二個類的fun的功能是打印2,你建一個類的對象,調fun,想打印1就能打印1,想打印2就能打印2,這就是多態,這就是多種形態,這也就是我們代碼中需要達到的要求
多態的本質:靈活的復用
多態的前提:繼承的基礎上
多態的實現:虛函數(有的人把重載這些也當作多態,靜態的多態,這種東西看個人理解,不用扣這些字眼,下面才是重中之重---虛函數)
虛函數關鍵字:virtual
知識點一:
class A void A::fun() class B : public A void B::fun()
{ { { {
public: printf("1"); public: printf("2");
virtual void fun(); } virtual void fun(); }
}; };
B *p = new B; p->fun();需求:不碰最後一行代碼,怎麼能調到A中的fun();
我們講一下虛函數的原理
當類中有虛函數,建類的對象,對象空間的前四個字節放的是虛表地址,通過虛表地址找到虛表,虛表中有這個類的所有虛函數的地址
當繼承有虛函數的類後,例如上面的B類,B類對象的前四個字節就有字節的虛表,如果B類有自己的虛函數,B類對象前四個字節是虛表的地址,地址找到的是自己類的虛函數地址----如果B類沒有自己類的虛函數,它仍有虛表(繼承),虛表找到的虛函數地址是父類(即上面A類)虛函數的地址
vc7S19PA4LXEZnVux7DD5tKyvNPBy9Dpuq/K/bXEudi8/NfWxNijrNXiyse49ry8x8k8L3A+CjxwPjxzdHJvbmc+t8DWudf308M8L3N0cm9uZz48L3A+CjxwPsjnufvT0NK7zOzT0NK7uPZDwOC8zLPQwcvO0s/W1Nq1xNfTwOBCwOCjrMTHQsDgvs2zycHLuLjA4KOsvajBy0PA4LXEttTP86OsQ8DgttTP89PQ19S8urXEZnVuuq/K/aOsztK1xNKqx/PKx7X308NDwOC1xGZ1brqvyv2jrLWrysfI57n709DIy7W3wtK78tXfsrvH5bP+o6y9q7XDtb1DwOC21M/ztdjWt7XE1rjV68e/16qzyULA4LXE1rjV66Ostfe1vbXEvs3Kx0LA4LXEZnVuuq/K/cHLPC9wPgo8cD7Wqsq2tePI/aO6PHN0cm9uZz7Q6c72ubk8L3N0cm9uZz6jqNOmuLbPwsPm1eLW1sfpv/ajqTwvcD4KPHA+z8LD5tXitcDM4tPQyrLDtM7KzOLC8DwvcD4KPHA+PHByZSBjbGFzcz0="brush:java;">calss A class B
{ { A *p = new B;
public: public: delete p;
char *p; char *t;
A(){ p = new char[20]; } B(){ t = new char[20]; }
~A(){ delete p; } ~B(){ delete t; }
}; };我們看一下反匯編
這裡Cs是子類,就是上面的B,上面的代碼執行匯編是這樣,看到01001757行代碼調用子類的析構
所以這道題是B類的成員指針new出的空間洩漏了
當我們將父類的析構函數前加個virtual再看匯編
01001878調用的edx裡面的內容在子類析構後最後調父類的析構
虛析構,調子類的析構---調父類析構
順序為什麼是先子後父呢---你要子類還用著,就析構了父類不就野指針了~~
虛析構是個好習慣
知識點四:純虛函數
虛函數聲明的時候後面寫 = 0,這個類就是抽象類,這個函數就是純虛函數
擁有純虛函數的類不能建對象
如果HR問我純虛函數,我就說 =0和不能建這個類的對象,我不會說抽象類這些概念,什麼叫抽象
什麼時候用到純虛函數,就是這個類你確定以後不會建對象了,就寫成純虛函數