我试图"修复" this answer中的示例,用于演示如何调用纯虚函数。
#include <iostream>
using namespace std;
class A
{
int id;
public:
A(int i): id(i) {}
int callFoo() { return foo(); }
virtual int foo() = 0;
};
class B: public A
{
public:
B(): A(callFoo()) {}
int foo() { return 3; }
};
int main() {
B b; // <-- this should call a pure virtual function
cout << b.callFoo() << endl;
return 0;
}
但是我没有得到运行时错误here (with C++ 4.9.2),而是输出3.我尝试使用Borland C ++ 5.6.4,但是我遇到了访问冲突。我认为foo()
在调用基类的构造函数时应该是纯虚拟的。
谁错了?我应该尝试更多的编译器吗?我是否正确理解虚函数?
答案 0 :(得分:14)
您的代码具有未定义的行为:在初始化所有基类之前,在对象(甚至是非虚拟对象)上调用成员函数是UB。 C ++ 14(n4140)12.6.2 / 14,强调我的:
可以为正在构建的对象调用成员函数(包括虚拟成员函数,10.3)。 类似地,正在构造的对象可以是
typeid
运算符(5.2.8)或dynamic_cast
(5.2.7)的操作数。 但是,如果这些操作是在 ctor-initializer (或直接调用的函数)中执行的 或者在基类的所有 mem-initializers 完成之前,间接来自 ctor-initializer ,结果 操作未定义。 ...
ctor-initializer 是:
之后的完整列表。 mem-initializer 是此列表的一个元素。
答案 1 :(得分:5)
语句B b;
将默认构造函数调用到B
。
在构建B
时,构建与B
无关的内容,直到A
完全构建。
因此,在尝试调用callFoo()
时,行为未定义,因为您不能依赖v-table来设置类B
。
总结:在构造抽象类期间调用纯虚函数的行为是未定义的。