——編譯器對非虛方法使用靜態聯編(編譯時匹配),對虛方法使用動態聯編(運行時匹配),
- 未使用虛方法時,指標型別在編譯時已知,因此編譯器在編譯時,可以將成員方法關聯到相應的類,這被稱為靜態聯編;
- 使用虛方法時,通常只有在運行程式時才能確定物件型別,所以編譯器生成的代碼在程式執行時將成員函式關聯到相應的類,這被稱為動態聯編,
靜態聯編比動態聯編效率高,
虛函式的作業原理,
虛函式,
重新定義成員函式(改變函式特征標),
重新定義多載的成員函式,
效率
為使程式能夠在運行階段進行決策,必須采取一些方法來跟蹤基類指標或參考指向的物件型別,這增加了額外的處理開銷,因此下列情況更適合靜態聯編:
- 類不會用作基類
- 派生類不重新定義基類的任何方法
因此靜態聯編被設定為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();}
-----
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/4985.html
標籤:C++
上一篇:vs2019編譯gdal3.1.0報錯 (filemanager.obj) : error LNK2001: 無法決議的外部符號 __imp_SHGetFolderPathW
