[英]C++ virtual destructor & vtable
我對虛擬析構函數和vtable有一些特定的問題。
假設我有以下代碼:
class Base
{
public:
virtual ~Base();
};
class Child : public Base
{
public:
~Child();
};
問題:
下面的解釋假設編譯器使用的虛擬調度實現基於虛擬表。
每個帶有虛方法(聲明或繼承)的類都有自己的虛表。 如果子類重寫基類中的虛擬成員函數,則指向該重寫函數的指針將放置在類的vtable中; 否則,將保留指向基類實現的指針。
添加第一個虛擬函數會使類實例的大小增加vtable指針的大小。 第一個函數之后的虛函數不會增加實例的大小。
由於~Base
是虛擬的,因此即使省略了virtual
關鍵字, ~Child
也是虛擬的。 如果有覆蓋,則virtual
關鍵字是可選的。
通過new運算符創建Child類型的實例,然后刪除...是否將調用Base析構函數?
不在原始問題代碼中,因為您沒有Child
從Base
繼承。
假設這是一個錯誤,我們修復它,然后~Base
將在銷毀了一個名為Child
,即使它不是虛擬的,只是因為基類的子對象被銷毀的銷毀的正常序列的一部分。
原因虛析構函數是這樣,你可以刪除一個Child
通過 Base *
,仍然有~Child
正確地調用。
例如:
struct Base { ~Base(); };
struct Child: Base { ~Child(); };
struct VBase { virtual ~VBase(); };
struct VChild: VBase { ~VChild(); };
這適用於兩個層次結構:
template <typename Derived>
void test_static() {
Derived d;
}
test_static<Child>(); // ~Child then ~Base invoked when d is destroyed
test_static<VChild>(); // ~VChild then ~VBase invoked when d is destroyed
但這僅適用於虛擬析構函數:
template <typename Derived, typename Base>
void test_dynamic() {
std::unique_ptr<Base> p(new Derived);
}
test_dynamic<Child, Base>; // only ~Base invoked when p destroyed
test_dynamic<VChild,VBase>; // ~VChild then ~VBase invoked as before.
至於vtable的問題,它是一個實現細節,它是否存在,如果存在,是否存在,您不必擔心。
每個帶有虛方法(聲明/繼承)的類都有自己的虛表(vtable)。 當將虛擬方法(不是析構函數的任何方法)聲明為虛擬方法時,派生類中該方法的所有替代都會自動成為虛擬方法。 編譯器還在具有虛擬方法的任何此類的開頭添加_vptr。 創建類的對象時,此_vptr將被填充,並將指向該類的vtable。 虛擬析構函數的處理方式與任何其他虛擬函數相同。 在您的示例中,由於〜Base是虛擬的,因此〜Child也將是虛擬的。
假設您這樣做:
Child *child = new (class Child);
delete(child);
在這里,child-> _ vptr將指向Child的vtable。 因此,在刪除過程中,〜Child將首先被調用,隨后被稱為〜Base(以相反的順序構造)。
或者,如果您這樣做,
Base *base = new (class Child);
delete(base);
在這里,base-> _ vptr將指向Child的vtable。 因此,在刪除過程中,將先從vtable調用〜Child,然后再調用〜Base。
在gdb中,我們可以通過運行以下命令來驗證_vptr,
"info vtbl base" or "print *base"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.