8

这不是关于“何时创建 VTABLE?” . 相反,什么时候应该初始化 VPTR?它是在构造函数的开头/结尾还是构造函数之前/之后?

A::A () : i(0), j(0)  -->> here ?
{
  -->> here ?
  //...
  -->> here ?
}
4

3 回答 3

19

虚拟调用的机制(通常是一个 v-table,但不是必须的)是在ctor-initializer期间、基础子对象构建之后和成员构建之前设置的。部分[class.base.init]法令:

可以为正在构建的对象调用成员函数(包括虚拟成员函数,10.3)。类似地,正在构造的对象可以是运算typeid符 (5.2.8) 或dynamic_cast(5.2.7) 的操作数。但是,如果这些操作在基类的所有mem-initializer完成之前在ctor-initializer(或直接或间接从ctor-initializer调用的函数中)执行,则操作的结果是未定义的。

实际上,在基类子对象的构建过程中,虚函数机制是存在的,但它是为基类设置的。[ class.cdtor] 节说:

成员函数,包括虚函数 (10.3),可以在构造或销毁 (12.6.2) 期间调用。当从构造函数或析构函数直接或间接调用虚函数时,包括在类的非静态数据成员的构造或销毁期间,并且调用适用的对象是x正在构造的对象(调用它)或破坏,调用的函数是构造函数或析构函数类中的最终覆盖者,而不是在派生更多的类中覆盖它。如果虚函数调用使用显式类成员访问 (5.2.5) 并且对象表达式引用x该对象的基类子对象的完整对象或其中之一,但不是x其基类子对象或其基类子对象之一,则行为未定义。

于 2011-07-06T05:32:35.870 回答
3

它在基类和派生类的构造函数之间初始化:

class Base { Base() { } virtual void f(); };
class Derived { Derived(); virtual void f(); };

当原始内存转换为 Base 对象时会发生这种情况。在构建对象期间将 Base 对象转换为 Derived 对象时会发生这种情况。破坏物体时同样明显地发生相反的情况。即每次类型改变时,vtable 指针都会改变。(我确定有人评论说 vtables 不需要根据标准存在。)

于 2011-07-06T05:26:23.823 回答
0

这篇 msdn 文章详细解释了它

那里说:

“最终的答案是……正如你所料。它发生在构造函数中。”

所以..
A::A () : i(0), j(0)
{
-->> 这里!
//...
//
}

但要小心,假设你有一个类 A,以及一个从 A 派生的类 A1。

  • 如果你创建一个新的 A 对象,vptr 将被设置在 A 类的构造函数的开头
  • 但是如果你要创建一个新对象 A1:

“当你构造一个 A1 类的实例时,这是整个事件序列:

  1. A1::A1 调用 A::A
  2. A::A 将 vtable 设置为 A 的 vtable
  3. A::A 执行并返回
  4. A1::A1 将 vtable 设置为 A1 的 vtable
  5. A1::A1 执行并返回 "
于 2014-03-24T14:20:14.800 回答