[英]How is virtual function table generated in subclass
所以我知道在 C++ 中,虛擬方法用於存儲在表中的每個類,每個實例都有一個指向該表的指針。 所以我的問題是子類表的樣子。 我將提供一個匯編指令:
vtable for Derived:
.long 0
.long _typeinfo for Derived
.long _Derived::set()
.globl _vtable for Base
.section .rdata$vtable for Base,"dr"
.linkonce same_size
.align 4
所以,從這里我可以看到 Derived 有一個虛方法,它是set()
,但讓我煩惱的部分是 Base 的 vtable。 Derived vptr 是保存指向 Base vptr 的指針還是存儲在 Derived 的 vtable 中。 我注意到在代碼編譯器中只將 vtable 存儲在對象的 0 地址處,一次在 Base 構造函數中,一次在 Derived 中。 為什么不覆蓋 vtable?
PS我真的不明白指令
編輯:
class Base{
virtual void print() {
printf("Base");
}
}
class Derived : Base{
virtual void print(){
printf("Derived");
}
}
簡單的答案是:這取決於編譯器。 該標准沒有規定這應該如何實施,只規定了它應該如何表現。
在實踐中,實現往往只是有一個派生的 vtable,它以與基礎 vtable 相同的結構開始,而不是在末尾附加派生類的方法(也就是說,派生類中的新方法,而不是覆蓋)。
vtable 指針只是指向整個表的開頭。 如果對象是通過基指針類型訪問的,那么任何人都不應超越基類方法的末尾。
如果指針是派生類型的,那么同一個指針將允許訪問表中進一步向下訪問派生類中聲明的虛擬方法。
附錄:多重繼承
多重繼承遵循相同的基本概念,但由於顯而易見的原因,它很快變得復雜。 但有一個重要特征需要牢記。
多派生類的每個基類都有一個 vtable 指針,指向不同的 vtable 或同一 vtable 中的不同位置(取決於實現)。
但重要的是要記住每個對象的每個直接基類都有一個。
因此,如果您有一個帶有一個int
數據和三個直接基類的多派生類,則每個對象的大小實際上是 16 字節(在 32 位系統上;在 64 位系統上更多)。 4 個用於int
,每個 vtable 指針各 4 個。 當然,還有每個基類本身的大小。
這意味着在 C++ 中,接口並不便宜。 (顯然在 C++ 中沒有真正的接口,但是一個沒有數據和只有純虛方法模擬它的基類。)每個這樣的接口花費每個對象一個指針的大小。
在像 C# 和 Java 這樣的語言中,接口是語言的一部分,有一種稍微不同的機制,所有接口都通過單個 vtable 指針路由。 這稍微慢一點,但意味着每個對象只有一個 vtable 指針,無論實現了多少接口。
出於設計原因,我仍然會遵循 C++ 中的界面樣式方法,但始終要注意這種額外的開銷。
(這些甚至都沒有涉及虛擬繼承。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.