因此,当在ctor/dtor基类中使用派生类并调用成员函数(包括虚拟)时,无论this是否通过指针,都会调用相关类的函数。
怎么会?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;
}
Run Code Online (Sandbox Code Playgroud)
在ctors/dtors中,调用创建/销毁对象的成员函数。
Nic*_*las 13
对象就是它的类型……直到它不是。
根据 C++ 的规则,对象的构造函数按特定顺序调用。由于派生类实例始终是基类实例,因此需要在派生类实例之前调用基类实例构造函数。
但如果是这样的话,那么调用基类构造函数时对象是什么?派生类构造函数甚至还没有启动,因此将其视为派生类实例还没有意义。
所以事实并非如此。
因此,在派生类初始化期间执行基类构造函数期间,所有virtual调用的工作方式就好像该类就是:基类实例。它还不是派生类类型的实例,因此您还不能调用派生类的任何成员。
我的意思是,是的,您可以static_cast访问派生类实例,但使用这样的指针会产生未定义的行为,因为您在初始化派生类类型之前访问该类型的对象。
相反的情况发生在析构函数中。首先调用派生类的析构函数,然后调用基类。但是派生类析构函数完成后......该对象不再是派生类实例。因此,virtual基类析构函数中的任何调用都会转到基类方法。
在基于 vtable 的实现中,此行为是通过在初始化期间的各个点更改构造函数/析构函数之间的 vtable 指针来实现的。基类构造函数将 vtable 设置为指向基类 vtable。当派生类析构函数启动时,它会将 vtable 设置为指向派生类 vtable。
| 归档时间: |
|
| 查看次数: |
265 次 |
| 最近记录: |