析构函数无法解释的行为
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
你忘记了类
之间的继承
这将在您执行 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
本题中: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
你忘记了类
之间的继承
这将在您执行
delete
行时立即触发 undefined behaviorA * 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