程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 深刻解析C++中的虛函數與多態

深刻解析C++中的虛函數與多態

編輯:關於C++

深刻解析C++中的虛函數與多態。本站提示廣大學習愛好者:(深刻解析C++中的虛函數與多態)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻解析C++中的虛函數與多態正文


1.C++中的虛函數
C++中的虛函數的感化重要是完成了多態的機制。關於多態,簡而言之就是用父類型其余指針指向其子類的實例,然後經由過程父類的指針挪用現實子類的成員函數。這類技巧可讓父類的指針有“多種形狀”,這是一種泛型技巧。所謂泛型技巧,說白了就是試圖應用不變的代碼來完成可變的算法。好比:模板技巧,RTTI技巧,虛函數技巧,要末是試圖做到在編譯時決定,要末試圖做到運轉時決定。

對C++ 懂得的人都應當曉得虛函數(Virtual Function)是經由過程一張虛函數表(Virtual Table)和一個指向虛函數表的指針(vptr)來完成的。虛函數表,簡稱為vtbl,虛函數表表對完成多態起著相當主要的感化。在這個表中,重要保留了一個類中的虛函數的地址,這張表處理了繼續、籠罩的成績,包管其內容能真實反響現實的函數。每個包括虛函數的類的實例都包括一個cptr指針,指向虛函數表的首地址。我們可以經由過程這個指針找到要拜訪的虛函數的,完成虛函數的挪用重要包含:找到虛函數表的首地址(vptr),經由過程cptr找到要應用虛函數地址,挪用虛函數。那末應用虛函數年夜家總要斟酌效力的成績,現實上為了進步效力,C++的編譯器是包管虛函數表的指針存在於對象實例中最後面的地位,這是為了包管取到虛函數表的有最高的機能,這意味著我們經由過程對象實例的地址獲得這張虛函數表,然後經由過程遍歷表便可以找到個中的虛函數的地址,然後挪用響應的函數。無妨看看上面的代碼:

#include <iostream>

using namespace std;

class Base
{
public:
    virtual void f() { cout << "Base::f" << endl; }
    virtual void g() { cout << "Base::g" << endl; }
    virtual void h() { cout << "Base::h" << endl; }
};

typedef void(*Fun)(void);


int main()
{
    Base b;
    Fun pFun = NULL;
    cout << "虛函數表地址:" << (int*)(&b) << endl;
    cout << "虛函數表 — 第一個函數地址:" << (int*)*(int*)(&b) << endl;
    pFun = (Fun)*((int*)*(int*)(&b));
    pFun();
    return 0;
}

經由過程這個示例,可以看到,經由過程強行把&b轉成int *,獲得虛函數表的地址(vptr),然後,再次取址便可以獲得第一個虛函數的地址了,也就是Base::f(),這在下面的法式中獲得了驗證(把int* 強迫轉成了函數指針)。經由過程這個示例,我們便可以曉得假如要挪用Base::g()和Base::h(),其代碼以下:

(Fun)*((int*)*(int*)(&b)+0); // Base::f()

(Fun)*((int*)*(int*)(&b)+1); // Base::g()

(Fun)*((int*)*(int*)(&b)+2); // Base::h()

可以看看虛函數表的圖是怎樣畫的:

            

年夜家都曉得,多態是經由過程繼續完成的,那末我們要說說虛函數繼續的成績。繼續就觸及到了虛函數的籠罩了,現實上不被籠罩的虛函數和多態又有甚麼接洽呢?這裡我們評論辯論有籠罩的虛函數表是甚麼樣的,假定存鄙人面的繼續關系:

        

看看虛函數表現甚麼樣的:

        

可以發明,Base::f()被籠罩了,如許若把Derive的實例賦值給一個基類Base指針pBase,經由過程pBase->f();則拜訪的是子類中的f()也就是完成了多態。那末虛函數表中的內容究竟是怎樣樣的呢?可以看看上面的四句話就會明確!

1.虛函數依照其聲明次序放於表中。

2.父類的虛函數在子類的虛函數後面。

3.籠罩的f()函數被放到了虛表華夏來父類虛函數的地位。

4.沒有被籠罩的函數照舊。

2.用虛函數完成多態
看看上面的多態的代碼:

#include <iostream>

using namespace std;

class Base
{
public:
    virtual void Print()
    {
        cout<<"Base::Print()"<<endl;
    }
};
class Derive : public Base
{
public:
    virtual void Print()
    {
        cout<<"Derive::Print()"<<endl;
    }
};
int main()
{
    Derive derive;
    Base *pBase = &derive;
    pBase->Print();
    return 0;
}
//多態代碼

完成虛函數的代碼,必定要切記:必定是基類的指針指向子類的對象的地址。起首試著懂得一下用虛函數完成多態的道理,假如其實沒懂得為何虛函數能完成多態,又為何如許完成多態,上彀再搜一搜相干的材料!!!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved