为什么这不是纯虚函数的调用?

Wol*_*olf 10 c++ pure-virtual

我试图在这个答案中 "修复"这个例子,以演示如何调用纯虚函数.

#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;
}
Run Code Online (Sandbox Code Playgroud)

但是我没有得到运行时错误(使用C++ 4.9.2),但输出3.我尝试使用Borland C++ 5.6.4,但是我遇到了访问冲突.我认为foo()在基类的构造函数的调用中应该是纯虚拟的.

谁错了?我应该尝试更多的编译器吗?我是否正确理解虚函数?

Rei*_*ica 14

您的代码具有未定义的行为:在初始化所有基类之前,在对象(甚至是非虚拟对象)上调用成员函数是UB.C++ 14(n4140)12.6.2/14,强调我的:

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

ctor-initializer是以下的完整列表:.mem-initializer是此列表的一个元素.


Bat*_*eba 5

该语句B b;调用默认构造函数B.

在构建时B,在完全构造B之前不构造任何相关的东西A.

因此,在尝试调用时callFoo(),行为是未定义的,因为您不能依赖v-table来B设置类.

总结:在构造抽象类期间调用纯虚函数的行为是未定义的.