我已经在许多地方(例如here)阅读了关于人们获得一个名为"的纯虚拟方法的问题。 运行时时出错和程序崩溃。 This answer说
大多数编译器将这样的vtable条目分配给存根,该存根在中止程序之前发出错误。
和this one甚至说Itanium ABI指定了该存根的内容。
问题是:我在编辑器(GCC 6.4.1)在编译时中捕获的所有尝试都是未定义的引用。例如,当从抽象类的构造函数调用纯虚函数时,我会收到警告
pure virtual ‘virtual int X::f()’ called from constructor
但同时根本没有为X::f()
生成任何代码,所以接下来是
undefined reference to 'X::f()'
并且编译失败。这似乎是一种在运行时防止错误的非常简单的方法。在哪种情况下,我的编译器实际上需要生成上述存根?或者它是否足够聪明,足以及早发现所有可能的病理情况?
答案 0 :(得分:10)
通常它会在构造函数中间接调用。这是一个最小的例子:
#include <iostream>
struct X {
virtual void foo() = 0;
void bar() { foo(); }
X() { bar(); std::cout << "X"; }
};
struct Y : X {
void foo() override {}
};
int main() {
Y y;
return 0;
}
如果编译器直接出现在c内,则编译器必须静态绑定调用(因此可以为纯虚函数生成有用的错误消息)。但是当调用是间接的,来自另一个成员时,必须动态调度它。
当然,Y
部分在X
的构造过程中尚未构建,因此整个事物在未定义的行为中坍塌。