簡體   English   中英

C ++虛擬析構函數和vtable

[英]C++ virtual destructor & vtable

我對虛擬析構函數和vtable有一些特定的問題。

假設我有以下代碼:

class Base
{
public:

    virtual ~Base();

};

class Child : public Base
{
public:

    ~Child();
};

問題:

  1. vtable存儲在哪里? 它是否總是在基類中,而所有子類都只是保持指向它的指針?
  2. 添加虛擬方法只會使sizeof(class)增加8個字節,對嗎? (假設是64位系統)如果基類存儲表,該如何處理?
  3. 通過new運算符創建Child類型的實例,然后刪除...是否將調用Base析構函數? (我問是因為Child類的析構函數不是虛擬的……是否意味着它僅影響Child的子類?)。

下面的解釋假設編譯器使用的虛擬調度實現基於虛擬表。

  1. 每個帶有虛方法(聲明或繼承)的類都有自己的虛表。 如果子類重寫基類中的虛擬成員函數,則指向該重寫函數的指針將放置在類的vtable中; 否則,將保留指向基類實現的指針。

  2. 添加第一個虛擬函數會使類實例的大小增加vtable指針的大小。 第一個函數之后的虛函數不會增加實例的大小。

  3. 由於~Base是虛擬的,因此即使省略了virtual關鍵字, ~Child也是虛擬的。 如果有覆蓋,則virtual關鍵字是可選的。

通過new運算符創建Child類型的實例,然后刪除...是否將調用Base析構函數?

不在原始問題代碼中,因為您沒有ChildBase繼承。

假設這是一個錯誤,我們修復它,然后~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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM