C++多態的使用


一、多態有靜態多態和動態多態:

1、靜態多態:函數重載和運算符重載屬於靜態多態,復用函數名

2、動態多態:派生類和虛函數實現運行時多態

二、靜態多態和動態多態的區別

1、靜態多態函數地址早綁定:在編譯階段確定函數地址

2、動態多態的函數地址晚綁定:運行階段確定函數地址

三、動態多態滿足條件

1、有繼承關系

2、子類重寫父類虛函數

四、動態多態的使用

父類的指針或者引用 執行子類對象

 

代碼:

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 5; class Animal { public: virtual void speak() { printf("Animal is Speaking\n"); } }; class dog : public Animal { public: virtual void speak()    //這里的virtual可寫可不寫
 { printf("dog is Speaking\n"); } }; class cat : public Animal { public: virtual void speak()    //這里的virtual可寫可不寫
 { printf("cat is Speaking\n"); } }; void test1(Animal &a) { a.speak(); } void test2(Animal *a) { a->speak(); } int main() { dog g; cat t; test1(t); dog * ptr = &g; test2(ptr); return 0; }

多態原理:

如果把上面main函數內容換成

 
         
class Animal
{
public:
    void speak()
    {
        printf("Animal is Speaking\n");
    }
};
int main() { Animal * a=NULL; a->speak(); return 0; } /* 輸出: Animal is Speaking */

上面代碼說明了就算沒有對變量a實例化一個對象,但是調用的方法仍然是看變量a的左邊(也就是a的類型)。但是多態中我們發現變量a調用的方法實際上和a的類型無關,這一點就需要把函數變成虛函數,也就是在函數前面加上關鍵字virtual。

 

例如Animal類,當它內部的speak函數不是虛函數的時候,你的sizeof(Animal)的值是等於1的(因為方法和變量是分開存儲的,而且Animal類沒有成員變量,這就相當於Animal是一個空對象)。但是當內存speak函數是虛函數的時候,你的sizeof(Animal)的值是等於4或者8(這要看操作系統,因為實際上這個時候類內部會出現一個指針vfptr(virtual function pointer 虛擬函數表指針),在32位操作系統上指針占4個字節)。

vfptr會指向一個虛擬函數表(vftable),虛擬函數表里面記錄的是這個類的虛函數的地址

我們使用visual studio查看類信息:

當我們的cat類沒有重寫Animal的speak方法時(這個時候會把父類的東西都繼承過來):

當cat類重寫Animal的speak方法時:

 

我們接着對之前那個代碼分析一下:

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 5; class Animal { public: virtual void speak() //這多加了virtual { printf("Animal is Speaking\n"); } }; int main() { Animal * a=NULL; a->speak(); }

這個代碼的輸出是什么也沒有,為什么不加virtual就有輸出,加了就沒有輸出呢?

 

我認為加了virtual之后函數變成了虛函數,這個時候類內部會出現一個指針vfptr,但是你實例化的時候給a指針賦了一個NULL指針,也就是沒有給a分配內存,那么vfptr指針就沒有了,也就沒辦法找到vftable,也就沒辦法找到函數入口地址。(這是我認為的,不知道對不對,如果有錯的話,希望大家給我指出^_^)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM