首頁 >後端開發 >C#.Net教程 >詳解C++虛成員函數與動態聯編

詳解C++虛成員函數與動態聯編

hzc
hzc轉載
2020-07-01 15:33:062099瀏覽

推薦學習: 《c 教學

#-編譯器對非虛擬方法使用靜態聯編(編譯時匹配),對虛方法使用動態聯編(運行時匹配)。

  • 未使用虛擬方法時,指標類型在編譯時已知,因此編譯器在編譯時,可以將成員方法關聯到對應的類,稱為靜態聯編;
  • 使用虛擬方法時,通常只有在執行程式時才能確定物件類型,所以編譯器產生的程式碼在程式執行時將成員函數關聯到對應的類,這稱為動態聯編。

  靜態聯編比動態聯編效率高。

  虛函數的工作原理。

  虛函數。

  重新定義成員函數(改變函數特徵標)。

  重新定義重載的成員函數。

  效率

  為讓程式能夠在執行階段進行決策,必須採取一些方法來追蹤基底類別指標或引用指向的物件類型,這增加了額外的處理開銷。因此下列情況較適合靜態聯編:

  • 類別不會用作基底類別
  • #衍生類別不重新定義基底類別的任何方法

  因此靜態聯編被設定為C 的預設選擇。

  若要在衍生類別中重新定義基底類別的方法,則將它設為虛擬方法;否則設為非虛方法。

  虛擬函數的工作原理

  編譯器處理虛擬函數的方法是:為每個物件增加一個隱藏成員。隱藏成員中保存了一個指向·函數位址·陣列的指標。這種數組稱為虛擬函數表(vtbl),表中儲存了為類別物件進行宣告的虛擬函數的位址。

  衍生類別物件將包含一個指向獨立位址表的指標(即新建立一個表)。 (增加記憶體開銷)

  呼叫虛擬函數時,程式將查看儲存在物件中的vtbl位址,然後轉向對應的函數位址表並在表中尋找位址。 (影響執行速度)

  總之,使用虛函數將在記憶體和執行速度上有一定的成本;即使非函數的效率比虛函數稍高,卻不具備動態聯編功能。

  建構子不能是虛函數。

  析構函數應為虛函數,除非類別不用做基底類別。

  友元函數不能是虛函數,因為友元不是類別成員,而只有成員可以是虛函數。

  如果衍生類別沒有重新定義函數,將使用該函數的基底類別版本(繼承它)。如果衍生類別位於衍生鏈中,則將使用最新的虛擬函數版本(指標或引用呼叫),基底類別版本被隱藏的情況除外。

   重新定義將隱藏基底類別方法:

class Dwelling
{public:    virtual void showperks(int a) const;
    ...
};class Hovel : public Dwelling
{public:    virtual void showperks() const;
    ...
}

  在衍生類別中重新定義函數(改變了參數特徵標),將隱藏同名的基底類別方法,而不是重載基底類別方法。

Hovel trump;
trump.showperks();    // validtrump.showperks(5);    // invalid

  若重新定義繼承的方法,應確保與原來的原型完全相同。如果傳回類型為基底類別參考或指針,則可以修改為指向衍生類別的參考或指標(傳回型別協變:即允許傳回型別隨類別類型的變更而變更)。

  如果基底類別宣告被重載了,則應在衍生類別中重新定義所有的基底類別版本;如果只定義了一個版本,則其它版本將被隱藏,派生類別物件將無法使用它們。

class Dwelling
{public:    virtual void showperks(int a) const;    virtual void showperks(double x) const;    virtual void showperks() const;
    ...
};class Hovel : public Dwelling
{    virtual void showperks(int a) const;    virtual void showperks(double x) const;    virtual void showperks() const;
    ...
};

   若不需要修改,則新定義可只呼叫基底類別版本:

  <span class="cnblogs_code"><span style="color: #0000ff;">#void </span> Hovel::showperks()<span style="color: #0000ff;">const</span> {Dwelling::showperks();}</span> 

以上是詳解C++虛成員函數與動態聯編的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除