1
#include<iostream>
using namespace std;

class A
{
public:
        int i;
        A() {cout<<"A()"<<endl;}
        ~A() {cout<<"~A()"<<endl;}
};
class B:public A
{
public:
        int j;
        B(): j(10)
        {
                this->i=20;
                this->~A();
        }
};

int main()
{
        B abc;
        cout<<"i="<<abc.i<<" j="<<abc.j<<endl;
}//main

两个问题:

  1. 为什么 A 的析构函数会像普通函数一样被调用而不是销毁对象?(或者只有当子类的析构函数调用基类的析构函数时,基类才会被销毁?)我正在尝试这个示例代码来了解析构函数的工作原理。因此,如果简单地调用析构函数不会破坏对象,那么显然还有其他类型的调用调用析构函数,然后才破坏对象。这种电话有什么特别之处,它是什么电话?
  2. 有没有办法在 B 的构造函数中为 A 设置一个初始化列表?像这样的东西:

    class B:public A
    { 
        B(): j(10), A():i(20) {}
    };
    
4

7 回答 7

5
  1. 基类的析构函数应该是虚拟的。在这里,因为它是在堆栈上创建的,所以这不是问题,但无论如何..
  2. 不可以,但是你可以class A()在 B 的构造函数的初始化列表中调用构造函数,像这样:
    B(): A( .. ), ...

A* a = new B();
//..
delete a;

除非析构函数是 virtual ,否则不会调用B 的析构函数。这就是为什么不应派生 STL 容器的原因——它们的析构函数不是虚拟的。class A

于 2010-10-26T08:30:03.017 回答
5
  1. 析构函数就像您可以调用的任何其他普通函数一样(但除非您使用新的位置,否则您永远不应该这样做)。当你调用delete一个对象时,会发生两件事:调用析构函数进行清理,然后operator delete调用析构函数来释放为对象分配的内存。这里没有发生第二步。

  2. 不,你不能这样称呼它。你可以做的是这样的事情:

    类 A { public: A(int n) : i(n){} };

    B类:公共A {公共:B():A(20),j(10){}};

于 2010-10-26T08:35:06.750 回答
3

对于点:

  1. 这是一个未定义的行为,但只有 ~A() 通过类 B 的实例被调用,因为 ~A() 没有被声明为虚拟的。在维基百科上查看更多信息。
  2. 不。对于派生类,首先调用您的父类,然后分配参数。

对于维基百科上的第 1 点):

没有虚拟析构函数,虽然删除类 B 的实例将正确调用 B 和 A 的析构函数,如果对象作为 B 的实例被删除,则通过指向其基类 A 的指针删除的 B 的实例将产生未定义的行为。

示例(对于第 2 点):

B(): A(), j(10) {}

或者

B(): A() {j = 10;}
于 2010-10-26T08:56:48.483 回答
3

@Nav:不,您对“破坏”的理解是错误的。当一个对象的析构函数被调用时,这个对象就被销毁了。你似乎相信它所驻留的记忆会完全消失,但这从未发生过。对象不再存在,但是对象通常会留下一些垃圾数据,如果您愿意打破 C++ 的规则并调用未定义的行为,那么您可以读取这些剩余字节,它们看起来像对象,并且由于没有运行时检查您是否正在访问有效对象,因此您通常可以将它们视为对象。你做什么。

这是非法的,是未定义的行为,但在实践中它通常有效。

再一次,析构函数不会物理蒸发内存。执行析构函数后,您的 RAM 仍然具有相同的容量。从概念上讲,一旦析构函数运行,对象就不再存在。但它包含的数据仍然存在于内存中。

于 2010-10-26T10:35:39.243 回答
2

1) C++ 中的析构函数调用顺序与构造函数调用顺序相反。所以首先派生类对象得到销毁,然后是基类对象。

2) 没有。

于 2010-10-26T08:35:54.667 回答
2

在您提供的代码中,您确实在破坏基类,因此i. 调用析构函数然后使用死对象是未定义的行为——它可能会工作,也可能会崩溃。

应该i是比int(例如 a vector)更复杂的东西,试图用它做任何事情都可能导致崩溃。

于 2010-10-26T09:50:48.663 回答
2

如果你自己调用 ~SomeClass(),显式地调用析构函数。这使对象(在这种情况下,对象的基类部分)处于破坏状态。

由于析构函数不是虚拟的,派生类的析构函数不会被调用,但 SomeClass 的基类也会被销毁。

试图通过仅使用 i 成员来确定 A 是否真的被破坏,这不是一个好的测试。事实上,您无法对此进行测试,因为使用该对象会导致未定义的行为。它可能有效,也可能无效(在您的情况下,它可能会打印“i=20 j=10”,但 i 已经被销毁)。

于 2010-10-26T09:56:22.913 回答