除了来自 leemes 的 C++ FAQ 链接,C++ 标准阻止它被调用,我将引用标准。
下面说,可以在构造函数/析构函数中调用虚成员函数,但它们充当“非虚函数”,您已经在 C++ 常见问题解答中知道了这一点。
可以调用成员函数,包括虚函数(10.3)
在建造或销毁期间 (12.6.2)。当一个虚函数
从构造函数或从
析构函数,包括在构造或销毁
类的非静态数据成员,以及调用的对象
apply 是正在构造或销毁的对象(称为 x),
调用的函数是构造函数中的最终覆盖器或
析构函数的类,而不是在派生更多的类中覆盖它。
如果虚函数调用使用显式类成员访问
(5.2.5) 和对象表达式是指 x 的完整对象
或该对象的基类子对象之一,但不是 x 或其之一
基类子对象,行为未定义。
它实际上还说,当从指针(指向自身)调用虚函数时,其类型不是自身的直接基类(在多重继承中),行为是未定义的。
示例(来自标准)
struct V {
virtual void f();
virtual void g();
};
struct A : virtual V {
virtual void f();
};
struct B : virtual V {
virtual void g();
B(V*, A*);
};
struct D : A, B {
virtual void f();
virtual void g();
D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {
f(); // calls V::f, not A::f
g(); // calls B::g, not D::g
v->g(); // v is base of B, the call is well-defined, calls B::g
a->f(); // undefined behavior, a’s type not a base of B
}
上述规则适用于其他动态绑定的东西,包括 typeid,这意味着您不能使用 typeid 来区分基构造函数中的派生类类型。
typeid 运算符 (5.2.8) 可以在构造过程中使用或
销毁(12.6.2)。在构造函数中使用 typeid 时(包括
非静态的 mem 初始化器或大括号或相等初始化器
数据成员)或在析构函数中,或在调用的函数中使用
(直接或间接)来自构造函数或析构函数,如果
typeid 的操作数是指正在构建的对象或
破坏,typeid 产生 std::type_info 对象,表示
构造函数或析构函数的类。如果 typeid 的操作数是指
正在构造或销毁的对象和静态类型
操作数既不是构造函数或析构函数的类也不是一个
在它的基础中,typeid 的结果是未定义的。