在抽象构造函数/析构函数中调用纯虚拟函数安全吗
Is it safe to call a pure virtual function in an abstract constructor/destructor, IF it has a body?
如果没有标有BODY的线,我知道这是不安全的。但有了它,这安全吗?
struct A
{
virtual ~A() { f(); }
virtual void f() = 0;
};
void A::f() {} // BODY
struct B : A
{
void f() {}
};
int main()
{
delete new B;
}
工作示例:http://ideone.com/9bRZ3i
不,那不安全。当A
构造函数(或析构函数)正在执行时,对象的类型是A
,而不是(不再是)B
对象。对f()
的调用将尝试调度到(仍然)纯虚拟函数,并导致未定义的行为。大多数实现都会捕捉到这一点,并使用错误消息终止应用程序,该消息指示调用了纯虚拟函数。
编辑后:
纯虚拟函数有一个定义,这意味着在不经过虚拟调度的情况下调用它是合法的。使用动态调度调用纯虚拟函数仍然是非法的。但是您可以将构造函数重写为:
A::~A() { A::f(); } // qualification disables dynamic dispatch
如果没有动态调度,代码将变为有效。
如果你想绕过虚拟调度并调用你定义的函数体,你必须限定函数名:
virtual ~A() { A::f(); } // OK.
否则,调用将启动虚拟调度,但仅对基类进行,因为派生类型的对象在其基类之前已经被销毁。
C++11§12.7/4直接解决了您的问题:
成员函数,包括虚拟函数(10.3),可以在构造或销毁(12.6.2)期间调用。当从构造函数或析构函数直接或间接调用虚拟函数时,包括在类的非静态数据成员的构造或销毁期间,调用所应用的对象是正在构造或销毁的对象(调用它x),调用的函数是构造函数或析构函数类中的最后一个重写器,而不是在更派生的类中重写它如果虚拟函数调用使用显式类成员访问(5.2.5),并且对象表达式引用x的完整对象或该对象的基类子对象之一,而不是x或其基类子对象之一时,则行为未定义。
然而,§10.4/6禁止使用纯虚拟函数进行此操作:
成员函数可以从抽象类的构造函数(或析构函数)中调用;从这样的构造函数(或析构函数)直接或间接地为正在创建(或销毁)的对象对纯虚拟函数进行虚拟调用(10.3)的效果是未定义的。
所以,它是UB。
"纯虚拟"的作用是从虚拟查找中隐藏函数定义。您永远不会从动态调度函数调用中获得纯虚拟函数的定义,除非可能是未定义行为的影响。
- C++无法定义虚拟函数 OUTER 类和头文件
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 尝试将unique_ptrs推送到向量时使用纯虚拟函数错误
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 类型擦除的std::function与虚拟函数调用的开销
- 重写虚拟函数和继承
- 用纯虚拟函数兜圈子
- 为什么使用存储在虚拟方法表中的地址调用虚拟函数的函数会返回垃圾?
- 禁止子函数调用父级的抽象(或虚拟)函数
- 无法在子类中使用虚拟函数C++
- 无法在派生对象上运行虚拟函数
- 我可以调用从 main() 覆盖的虚拟函数吗?
- 在 C++ 中将函数获取和设置为虚拟函数
- 使用在堆栈上创建的对象调用虚拟函数
- 为什么在这种情况下不调用我的虚拟函数实现?
- 在C++中使虚拟函数私有化
- 模板继承类中的虚拟函数
- 为什么构造函数的虚拟函数调用有时有效,但其他调用却无效
- doxygenc++虚拟函数和实现
- 如何从派生类函数中调用虚拟函数