【问题标题】:Does destructing objects stop the late binding?破坏对象会停止后期绑定吗?
【发布时间】:2021-06-22 20:46:56
【问题描述】:

考虑以下 C++ 类继承层次结构及其预期的多态行为。

#include <iostream>
using namespace std;

class A
{
public:
  A () { cout << "A constructor\n"; }
  virtual void display() { cout << "A display\n"; }
  virtual ~A() { cout << "A destructor\n"; }
  friend ostream& operator << (ostream &out, A &a) {
    a.display();
    return out;
  }
};

class B : public A
{
public:
  B () { cout << "B constructor\n"; }
  virtual void display() { cout << "B display\n"; }
  virtual ~B() { cout << "B destructor\n"; }
};

class C : public B
{
public:
  C () { cout << "C constructor\n"; }
  virtual void display() {cout << "C display\n";}
  virtual ~C() { cout << "C destructor\n"; }
};
int main()
{
  C c1;
  cout << endl; c1.display(); cout << endl;
  c1.~C();
  cout << endl; c1.display(); cout << endl;
  c1.~C();

  cout << "=================================================" << endl;

  C c2;
  cout << endl << c2 << endl;
  c2.~C();
  cout << endl << c2 << endl;
  c2.~C();

  return 0;
}

我的理解是 display 成员函数是虚拟的,因此将始终如此。在主程序的顶部,它表现良好;也就是说,当我们调用 c1.display() 时,它会打印“C display”消息。即使在破坏 c1 对象之后也是如此。

在下半部分,我们不调用显示函数。相反,我们调用输出流友元函数,该函数将依次调用显示成员函数。在这种情况下,它起初工作得很好;即 cout

但是当我们做同样的事情时 cout

我不明白?销毁对象会停止后期绑定吗?

【问题讨论】:

    标签: c++ inheritance polymorphism virtual-functions late-binding


    【解决方案1】:

    销毁一个对象使得继续调用该对象的成员函数是非法的。您的代码的行为是未定义的,并且您观察到的任何行为都不能在同一程序的运行中持续存在,更不用说不同的编译器标志或完全不同的实现了。

    但是,我们可以猜测您为什么会看到您报告的特定行为,但我们理解未来不应继续编译和运行此类代码,因为它的行为无法保证。

    很可能您的编译器正在对c1.display() 调用进行去虚拟化,因为它可以看到c1 的定义(因此知道它的动态类型是C)。因此,生成的代码可能根本不参考 vtable。这解释了为什么即使对象已被销毁,您仍然会看到“C 显示”。

    在c2 的情况下,对象是通过引用传递的,并且编译器可能没有足够积极地进行内联以对最终的display 调用进行去虚拟化。如果在c2被销毁后查询vtable,它可能会找到A的vtable,因为C对象的销毁过程最终必须重置A子对象的vptr指向A之前的vtable到A::~A 的执行(以防A::~A 调用任何虚函数)。这样就解释了“A display”消息。

    【讨论】:

    • 出色的分析......关于 OP 的代码是如何出错的。
    • 供参考:C++17 的第 6.8 1.3 和 6.8 7.2 节与观察到的行为相关。 § 15.4 16 也与代码相关,但不会导致问题中提到的行为。 § 15.7 3 很有趣(尽管与所讨论的代码没有直接关系),因为它涵盖了在构造函数和析构函数中调用的虚函数的解析。
    猜你喜欢
    • 1970-01-01
    • 2011-05-27
    • 2018-09-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    相关资源
    最近更新 更多