推薦學習: 《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中文網其他相關文章!