析构函数无法解释的行为

Unexplainable behaviour of destructor

本文关键字:无法解释 析构函数      更新时间:2023-10-16

在这个问题中:虚析构函数是如何工作的?

上面的答案有以下注释:

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

这似乎与注释不一致。

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

例如,假设类A和类C都在堆上分配了一个属性,并且需要清理它们。如何安全地编写这样的层次结构?注意:我目前并没有试图写这样的层次结构,请不要回答"不要,这是糟糕的设计"。此外,我知道智能指针可以解决这个问题,这更多的是为了确保我理解底层机制。

是否要求C类正确地清理A类属性?如果该财产是私有的,而不是受保护的或公共的,会发生什么?是我错过了什么,还是我误解了我所看到的?

用来运行这些测试的编译器

gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4

正如其他人所注意到的,您希望(确实需要)在这里使用继承。

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

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

#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
  1. 你忘记了类之间的继承

  2. 这将触发未定义的行为,只要你执行delete

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

我相信这就是你要找的

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;
  }

};

您这里所指的行为是派生类中的虚析构函数的行为,即继承了其他类的类。

还记得在编译c++时使用g++