cpp - vtable 指针是否在 construction/destruction 期间被更改

cpp - is vtable pointer being altered during construction/destruction

因此,在基 class 的 ctor/dtor 中使用派生 class 并调用成员函数(包括虚拟函数)时,是否通过 this指针与否,都会调用相关class的函数。

怎么会?对象的 vtable 指针是否在此过程中以某种方式被更改?因为,据我了解,除非使用多重继承,否则对象中通常只有一个 vtable 指针。


我有以下代码来举例说明我的意思:

#include <stdio.h>


class B {
    public:
    B()
        { printf("B constructor!\n"); f(); g(); }
    virtual ~B()
        { printf("B destructor!\n");  f(); g(); }
    virtual void f() 
        { printf("f() in B!\n"); }
    void g() 
        { printf("g() in B!\n"); }
    void h() 
        { printf("h() in B!\n"); }
};

class D : public B {
    public:
    D()
        { printf("D constructor!\n"); f(); g(); }
    virtual ~D()
        { printf("D destructor!\n");  f(); g(); }
    virtual void f() 
        { printf("f() in D!\n"); }
    void g() 
        { printf("g() in D!\n"); h(); }
};

int main()
{
    D *d = new D;
    B *b = d;
    delete b;
}

在ctors/dtors中调用了created/destructed对象的成员函数

对象是它的类型......直到它不是。

根据 C++ 的规则,对象的构造函数按特定顺序调用。因为派生 class 实例 始终是 基础 class 实例,所以需要在派生 [=] 之前调用基础 class 实例构造函数41=]实例.

但如果是这样的话,那么调用基 class 构造函数时的对象是什么?派生的 class 构造函数甚至还没有 启动 ,因此将它视为派生的 class 实例是没有意义的。

所以不是。

因此,在基 class 构造函数在派生 class 的初始化中执行期间,所有 virtual 调用都像 class 是:基础 class 实例。它不是派生class类型的实例,所以你不能调用任何派生class的成员。

我的意思是,是的,您可以 static_cast 到派生的 class 实例,但是使用这样的指针会产生未定义的行为,因为您正在访问派生的对象 class 在该类型被初始化之前输入。

相反的情况发生在析构函数中。派生的 class 析构函数首先被调用,然后是基础 classes。但是在派生的 class 析构函数完成后...对象 不再是 派生的 class 实例。因此,在基础 class 析构函数中的任何 virtual 调用都会转到基础 class 方法。

在 vtable-based 实现中,此行为是通过在初始化期间的各个点更改 constructors/destructors 之间的 vtable 指针来实现的。 base class 构造函数将 vtable 设置为指向 base class vtable。当派生的 class 析构函数启动时,它将 vtable 设置为指向派生的 class vtable.