——編譯器對非虛方法使用靜態聯編(編譯時匹配),對虛方法使用動態聯編(運行時匹配)。數組
靜態聯編比動態聯編效率高。函數
虛函數的工做原理。spa
虛函數。指針
從新定義成員函數(改變函數特徵標)。code
從新定義重載的成員函數。對象
效率blog
爲使程序可以在運行階段進行決策,必須採起一些方法來跟蹤基類指針或引用指向的對象類型,這增長了額外的處理開銷。所以下列狀況更適合靜態聯編:繼承
所以靜態聯編被設置爲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(); // valid trump.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; ... };
若是不須要修改,則新定義可只調用基類版本:
void Hovel::showperks()const {Dwelling::showperks();}
-----