代码之家  ›  专栏  ›  技术社区  ›  Nav MetroidFan2002

基类的析构函数在不破坏基类的情况下调用!

  •  1
  • Nav MetroidFan2002  · 技术社区  · 15 年前
    #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) {}
      };
      
    7 回复  |  直到 15 年前
        1
  •  3
  •   Stack Overflow is garbage    15 年前

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

    这是违法的,这是不明确的行为,但在实践中它经常有效。

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

        2
  •  5
  •   Naveen    15 年前
    1. 可以 打电话(但除非你使用新的位置,否则永远不要打)。当你打电话 delete operator delete 调用以释放为对象分配的内存。在这里,第二步不会发生。

    2. 不,你不能这样称呼它。你能做的就是这样:

      { 公众: A(int n):i(n){} };

      B类:公共A { 公众: };

        3
  •  5
  •   Kiril Kirov    15 年前
    1. 应该 虚拟化。在这里,因为它是在堆栈上创建的,所以没问题,但是无论如何。。
    2. class A() B的构造函数初始化列表中的构造函数,如下所示:
      B(): A( .. ), ...

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

    将 不 调用B的析构函数,除非 class A 是虚拟的 . 这就是为什么不应该派生STL容器-它们的析构函数不是虚拟的。

        4
  •  3
  •   Buhake Sindi Tesnep    15 年前

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

    关于维基百科的第一点:

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

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

    或

    B(): A() {j = 10;}
    
        5
  •  2
  •   user001    15 年前

    1)C++中析构函数调用顺序是构造函数调用顺序的逆序。因此,首先派生类对象得到destroy,然后派生基类对象。

    2) 没有。

        6
  •  2
  •   ipapadop    15 年前

    i . 调用析构函数然后使用死对象是未定义的行为-它可能工作,也可能崩溃。

    应该 是一件更复杂的事情 int (例如 vector ),试图对此做任何事情都可能导致崩溃。

        7
  •  2
  •   Jan    15 年前

    如果您自己显式调用~SomeClass(),则将调用析构函数。使对象(在本例中是对象的基类部分)处于已销毁状态。

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

    仅仅使用i成员来确定A是否真的被破坏,并不是一个好的测试。实际上,您不能测试它,因为使用对象会导致未定义的行为。它可能工作,也可能不工作(在您的情况下,它可能会打印“i=20j=10”,但我已经被销毁了)。