0

在许多资料中,书籍等都写着“不要在子类构造函数中调用 this->virtualFunction”,并且在一些资料中解释了为什么你不能这样做。因为在构建类的时刻根本没有创建。因此,将从子构造函数调用的虚函数将是基类的函数。这意味着在该类的子构造函数主体中,VPTR 指向基 VTABLE。

所以我的问题是,
当子类的 VPTR 被覆盖以在它的虚拟表上寻址时,对象构造的时刻是什么时候?我猜想一些自动生成的代码会在构造函数主体的末尾或在构造函数主体执行之后执行。

第二个问题是,
为什么在构建结束时会覆盖 VPTR?也许有一些重要的原因?为什么不能在开始构造函数体或构造基类之后覆盖 VPTR?

Child::Child() :
Base()
//<----- Why not here?
//members initialization
{
//<----- Why not here?
//code
}
4

2 回答 2

1

我不同意你为什么不应该调用虚函数的过于简单的理由。首先,VTABLE 实际上并没有由 C++ 标准定义,实际上是特定于实现的:

C++中的VTable是什么时候创建的?

标准允许从构造函数调用虚函数,并且实际上应该在该级别的层次结构中正确调用(有一些限制)

C++ 构造函数:为什么这个虚函数调用不安全? http://www.parashift.com/c%2B%2B-faq-lite/calling-virtuals-from-ctors.html

但是,有很多很多的理由不这样做。

  • 派生类的构造函数尚未被调用。对派生类的任何成员的任何访问都将产生未定义的行为。
  • 有一条经验法则,您应该使构造函数尽可能简单和愚蠢。这是因为构造函数中的错误处理可能是一个巨大的痛苦,因为没有调用析构函数,并且返回有意义的错误状态的唯一方法是抛出异常。
  • 这通常会破坏依赖倒置原则,并且可能会越界,并且通常会给代码带来高耦合。
于 2014-12-04T14:35:04.563 回答
1

在许多资料中,书籍等都写着“不要在子类构造函数中调用 this->virtualFunction”

我不信。通常建议不要从类构造函数调用虚函数,以避免在您希望它们调用最终覆盖而不是基类版本时造成混淆。如果它们在那里是纯虚拟的,那么你当然不能从基类中调用它们——这会产生未定义的行为。

在派生类构造函数中,它们是定义良好的,并且可以满足您的期望。

因此,将从子构造函数调用的虚函数将是基类的函数。

不,在孩子的构造函数体中,动态类型是Child,并且虚函数调用将使用Child覆盖。

当子类的 VPTR 将被覆盖以在其虚拟表上寻址时,对象构造的时刻是什么时候?

在所有基类构造函数完成之后,在子类成员初始化之前。Child成员函数,包括虚函数,可以从成员初始化器(但不是基类初始化器)或构造函数体中调用。

您需要小心地从成员初始化程序中调用它们,因为它们可能会访问未初始化的成员。但是在构造函数体内,所有的基础对象和成员都被初始化了,所以它们是相当安全的。

为什么在构建结束时会覆盖 VPTR?

它不是。它发生在您用 指示的第一点<----- Why not here?

于 2014-12-04T14:42:31.737 回答