[英]Disable dynamic binding (virtual table creation) in c++ for virtual functions
我最近遇到了一個C ++面試問題讓我非常好奇:
假設您錯誤地將某些C ++成員函數聲明為虛擬,但是(可能出於性能原因)您希望阻止編譯器為此函數創建v表。 也就是說,禁用動態功能綁定以支持靜態綁定。
你會如何實現這一目標? 此外,是否有一些C ++ 11具體的方法呢?
我知道沒有辦法強迫C ++編譯器禁用動態綁定,如果它支持這樣一個選項(不是所有的C ++編譯器都做,但大多數都是這樣),就不能強迫它編譯純C語言。 然而,這有點像用洗澡水甩掉嬰兒,因為它理論上禁用了不屬於C的所有C ++功能。
當然,還有C ++ 11中引入的final
標識符,它可以防止從類中進一步派生或覆蓋虛擬成員。 嚴格來說,這並不妨礙動態調度 - 它解決了一個不同的問題。
避免動態綁定的含義(感知或實際)的一種方法是避免使用或編寫具有虛擬成員函數的任何類,並且不創建類層次結構(即,不從具有虛函數的類派生)。 顯然,如果沒有正在運行的虛函數,則不需要虛函數調度,因此不需要動態綁定。
如果您知道對象的類型,則可以通過使用靜態分派來避免使用動態綁定,即明確命名要調用的函數。 例如,假設我們有一個類Base
,它提供一個名為foo()
的public
virtual
成員和一個名為Derived
的類,它繼承自Base
並覆蓋foo()
。 然后以下避免進行動態調度;
Base *b = new Derived;
b->Base::foo(); // static call; will not call `Derived::foo()`
b->Derived::Foo(); // incorrect static call. Will not compile since b is a pointer to Base not Derived
Derived *d = new Derived;
d->Derived::foo(); // static call of Derived::foo()
d->Base::foo(); // static call of Base::foo()
當然,如果使用對象的代碼依賴於對象的ACTUAL類型的知識,或者依賴於被調用的foo()
的特定變體,那么它的設計類型會破壞具有多態基類和其他類的目的。從中衍生出來的類。
在上面,編譯器仍將支持虛函數調用(vtable等,如果現在編譯器工作),這可能會影響創建和銷毀對象的過程。
另一種避免動態分派(或綁定)的技術是使用模板(有時稱為編譯時多態)。 本質上,模板可以假定類型提供一些接口(或一組操作),並且將使用具有該接口的任何類型的變量。 例如;
struct X
{
void foo();
};
template<class T> void func()
{
T x; // relies on T being instantiable (and destructible)
x.foo(); // relies on T having a member named foo()
}
// in some function somewhere where both X and func() are known to the compiler
func<X>();
此類模板不需要類型T
具有虛函數,因此不要依賴動態調度(綁定)。 但是,沒有什么能阻止這樣的模板函數與具有虛擬成員函數的類一起工作,因此這不會禁用動態綁定 - 它只允許程序員做出選擇以避免使用動態綁定。
如果我在采訪中被問到這個問題,我可能會指出上述所有問題,但是請不要說這個問題相當愚蠢。 一位熟悉C ++的面試官會意識到這一點,並且對你如何思考和解決這樣一個問題感興趣(畢竟管理層或客戶經常要求現實世界的開發人員滿足愚蠢或不切實際的要求,並且預計會變得機智足以避免告訴他們的經理或客戶他們是愚蠢的)。 如果面試官在沒有理解的情況下提出這個問題(或者沒有面試小組的其他成員了解房間內的情況),我也不想與該雇主合作。
您可以通過禁用RTTI來避免開銷...有一個編譯時間開關。
一旦啟用了RTTI禁用標志,對於dynamic_cast / typeid,不會有虛擬表分派的任何開銷。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.