繁体   English   中英

从 C++ 中的 class 析构函数调用虚拟 function

[英]Calling virtual function from a class destructor in C++

在构造函数或析构函数中调用虚函数的问题已经在许多其他问题和资源中讨论过,但我想澄清一些关于它的东西,我仍然感到缺失。

例如,在 Scott Meyers, Effective C++, Item 9 中有完整的解释。 但最后的评论是

在构造或销毁期间不要调用虚函数,因为这样的调用永远不会 go 到比当前执行的构造函数或析构函数更派生的 class

所以我想了解在什么意义上从构造函数或析构函数调用虚拟 function 是不安全的。

  • 因为虚拟表状态在析构函数中是“不确定的”,所以我可能会得到意外的运行时行为,这是否不安全?
  • 或者,从某种意义上说它是不安全的,因为我可能会得到与我预期不同的行为,所以它是不可维护的?

谢谢

因为虚拟表状态在析构函数中是“不确定的”,所以我可能会得到意外的运行时行为,这是否不安全?

C++ 标准没有讨论 vtable 实现。 它讨论了行为。 并且行为是调用被静态解析(好像)。

就实现而言,那些通常“恢复” vptr 使其指向当前被破坏的类的 vtable,在析构函数执行的早期。

或者,从某种意义上说它是不安全的,因为我可能会得到与我预期不同的行为,所以它是不可维护的?

取决于你的期望。 如果您知道呼叫是如何解决的,您将得到您所期望的

class Thing {
public:
    virtual ~Thing() { frombulate(); }
    void frombulate() const { do_frombulation(); }
private:
    virtual void do_frombulation() const = 0;
};

inline void Thing::do_frombulation() const {}

就像我说的,你可能知道会发生什么行为,所以即使do_frombulation是纯虚拟的,你也提供了一个实现。

如果不知道,您可能已经省略了空定义。 在这种情况下,您的程序将表现出未定义的行为(可能会崩溃,因为Thing的 vtable 中的该条目不会由有效地址填充)并且您可能会对此感到惊讶。 如果您直接在构造函数/析构函数体中调用未实现的纯虚拟do_frombulation ,编译器可能会通知您,但它无法检查所有执行路径。

从某种意义上说,我可能会得到意外的运行时行为,这是否不安全......

意外行为正是它不安全的意义。 该程序的读者或作者可能会期望调用虚拟 function 会调用最派生的覆盖。 这个假设在 detructor(也不是在构造函数)中是不正确的,这可能是出乎意料的。

...因为虚拟表状态在析构函数中是“不确定的”?

这种行为没有任何“不确定性”。

或者,从某种意义上说它是不安全的,因为我可能会得到与我预期不同的行为,所以它是不可维护的?

意外行为通常不同于人们预期的行为。 所以,是的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM