C++ 普通函數和虛函數調用的區別

來源:互聯網
上載者:User

標籤:輸出   void   int   null   尋找   問題   itblog   using   不同   

引出:寫個類A,聲明類A指標指向NULL,調用類A的方法會有什麼後果,編譯通過嗎,運行會通過嗎?

#include<stdio.h>#include<iostream>using namespace std;class base{    int a;public:    void fun(){        printf("base fun\n");    }};int main(){    base *b=NULL;    b->fun();}

看到這個的時候,一定以為運行會報錯吧。

但是奇蹟般的,編譯器輸出了:base fun

#include<stdio.h>#include<iostream>using namespace std;class base{    int a;public:    virtual void fun(){        printf("base fun\n");    }};int main(){    base *b=NULL;    b->fun();}

在看這個代碼,還以為會輸出base fun麼,又錯了,運行報錯!

為什麼會是這個結果?

#include<stdio.h>#include<iostream>using namespace std;class base{    int a;public:    virtual void fun(){        printf("base fun\n");    }        void fun2(){        printf("base fun\n");    }};int main(){    base *b=NULL;    b->fun();    b->fun2();}

可以發現,一個是虛函數,一個普通函數

在觀察下記憶體中得情況:

發現果然虛函數還沒在記憶體中,而fun2已經在記憶體中了

在看看彙編:

明顯發現虛函數的調用比普通函數多了好幾個步驟,

ecx 中放的this 指標,所以this=0(NULL),但是普通函數fun2放在全域記憶體區,所以可以訪問

而虛函數是根據虛函數表尋找的,這時沒有虛函數表,自然就沒法查到虛函數的地址了。

因為非虛函數的地址對編譯期來說“靜態”的,也就是函數地址在編譯期就已經確定了,執行個體地址對於非虛函數只是那個 this 指標參數。所以只要不訪問類的執行個體資料就沒什麼問題。而虛函數的地址,是先到執行個體的地址前面去尋找它的虛函數表所在的地址。然後從虛函數表裡取出該函數所對應的元素(虛函數表是一個函數指標數組)來call的。(當然一個已知的類的虛函數表的內容也是編譯期靜態,但不同類的虛函數表內容不同,即運行時多態的基礎)所以執行個體如果為NULL,是個有特殊意義的值,是會觸發執行階段錯誤的。

 

總結:類中的虛函數是動態產生的,由虛函數表的指向進行訪問,不為類的對象分配記憶體,就沒有虛函數表就無法訪問。

   類中的普通函數靜態產生,不為類的對象分配記憶體也可訪問。

C++ 普通函數和虛函數調用的區別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.