析构函数无法解释的行为

Unexplainable behaviour of destructor

本题中:How do virtual destructors work?

最上面的答案有以下注释:

Note that the destructor of the base class will be called implicitly after the destructor of the derived class finishes. This is a difference to the usual virtual functions.

我整理了一个快速示例程序来测试这个,

class A {
public:
  virtual ~A() {
    std::cout << "A DESTRUCTOR" << std::endl;
  }
};
class B {
public:
  virtual ~B() {
    std::cout << "B DESTRUCTOR" << std::endl;
  }
};
class C {
public:
  virtual ~C() {
    std::cout << "C DESTRUCTOR" << std::endl;
  }
};

int main(int argc, char** argv)
{
  A * aPtr = (A *)new C();
  C * cPtr = new C();

  delete aPtr;
  delete cPtr;
  return 0;
}

我得到的输出是

C DESTRUCTOR
C DESTRUCTOR

这似乎与注释不一致。

我的问题是,如何在需要多个析构函数的 class 层次结构中安全地实现析构函数 运行?

假设,例如,class A和class C都在堆上分配了一个属性,需要清理它们。我将如何安全地编写这样的层次结构?注意:我目前并没有尝试编写这样的层次结构,请不要用 "don't, it's bad design" 回复。另外,我知道智能指针可以解决问题,这更多是为了确保我了解底层机制。

是否需要 C class 正确清理 A class 属性?如果 属性 是私有的而不是受保护的或 public 会发生什么?我是不是遗漏了什么,或者误解了我所看到的?

编译器用于运行这些测试

gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
  1. 你忘记了类

  2. 之间的继承
  3. 这将在您执行 delete 行时立即触发 undefined behavior

    A * aPtr = (A *)new C();
    

我相信 this 就是您要搜索的内容

class A {
public:
  virtual ~A() {
    std::cout << "A DESTRUCTOR" << std::endl;
  }
};
class B : public A{
public:
  virtual ~B() {
    std::cout << "B DESTRUCTOR" << std::endl;
  }
};
class C : public B{
public:
  virtual ~C() {
    std::cout << "C DESTRUCTOR" << std::endl;
  }
};

int main(int argc, char** argv)
{
  A * aPtr = new C(); // The cast here is not needed
  C * cPtr = new C();

  delete aPtr;
  delete cPtr;
  return 0;
}

输出

C DESTRUCTOR
B DESTRUCTOR
A DESTRUCTOR
C DESTRUCTOR
B DESTRUCTOR
A DESTRUCTOR

更改为:

class A {
public:
  virtual ~A() {
    std::cout << "A DESTRUCTOR" << std::endl;
  }
};
class B : public A{
public:
  virtual ~B() {
    std::cout << "B DESTRUCTOR" << std::endl;
  }
};
class C : public B{
public:
  virtual ~C() {
    std::cout << "C DESTRUCTOR" << std::endl;
  }

};

你这里指的行为是derived 类中的virtual destructors的行为,意思是类 with inheritance of other 类.

另外记得用g++编译c++

正如其他人所指出的,您想要(确实需要)在这里使用继承。

他们没有注意到的是,编译器只允许您这样做,因为您在 确实 不应该使用的地方使用了强制转换。如果你需要使用强制转换,你 真的 应该坐下来,三思为什么 强制转换是必要的,并确定它在做什么真的是你想做的事。

如果没有强制转换,编译器将阻止编译损坏的代码。更正继承后,没有转换就可以了:

#include <iostream>

class A {
public:
  virtual ~A() {
    std::cout << "A DESTRUCTOR" << std::endl;
  }
};
class B : public A {
public:
  virtual ~B() {
    std::cout << "B DESTRUCTOR" << std::endl;
  }
};
class C : public B {
public:
  virtual ~C() {
    std::cout << "C DESTRUCTOR" << std::endl;
  }
};

int main(int argc, char** argv) {
  A * aPtr = new C();

  delete aPtr;
}

结果:

C DESTRUCTOR
B DESTRUCTOR
A DESTRUCTOR