【问题标题】:Override Destructor C++重写析构函数 C++
【发布时间】:2013-06-10 05:12:05
【问题描述】:

来自 C++ 常见问题解答:

[11.4] 我可以为我的班级重载析构函数吗? 没有。

我意识到这意味着您无法更改返回类型、参数类型或参数数量。我可能对单词的语法感到困惑,但是是否可以覆盖父级的析构函数?

class Child : public Parent {
public:
    virtual Parent::~Parent() {
        // New definition
    }
};

那么递归呢?

class Grandchild : public Child {
public:
    Child::Parent::~Parent() {
        // An even newer definition
    }
};

我读过thisrelated post,这让我觉得因为析构函数不是继承的,它们不能被覆盖,但我从未见过它明确说明过。

编辑:我对此进行了更改以反映我想要覆盖父级的析构函数这一事实,请注意子级和孙子级覆盖 ~Parent()。

我这样做的主要原因是为了维护 Parent 的接口,同时改变它的销毁方式(子类的全部原因)。我将有其他东西来管理所有 Parent 的创建,并在我选择的稍后时间显式调用它们的析构函数。

【问题讨论】:

  • 就像你说的,析构函数不是继承的。当子对象析构时,它会调用它自己的析构函数加上它的父析构函数。在子类中覆盖父母析构函数没有什么意义。
  • @yngum 当然析构函数是继承的。如果您没有在覆盖父类的子类中提供析构函数,则实际上是在继承基类析构函数。在派生类中重写父类的析构函数很有意义,就像您在下面给出的一些示例中看到的那样。
  • @PhilipStuyck:析构函数是继承的。如果你不声明析构函数,编译器会为你生成一个。隐式析构函数执行后自动调用基类析构函数。请参阅我的答案中的标准报价。
  • @PhilipStuyck:考虑一下,如果派生类继承了基类的析构函数,派生类的成员将如何销毁?
  • @PhilipStuyck:“......因此他们被继承了。”不,不继承析构函数。 12.4/3:“如果类没有用户声明的析构函数,则隐式声明析构函数。”

标签: c++ inheritance overriding destructor multiple-inheritance


【解决方案1】:

是的:您可以拥有virtual 析构函数,唯一的原因是在派生类中覆盖它们。

看起来像这样:

class Parent {
public:
    virtual ~Parent();
};

class Child : public Parent {
public:
    virtual ~Child();
};

class Grandchild : public Child {
public:
    ~Grandchild(); // virtual is inherited here
};

请注意,析构函数不像普通函数那样被 name 覆盖,因为名称始终是您要销毁其实例的类的名称。

还要注意,父类的析构函数也总是被调用,所以你不需要复制它们的清理代码:详细阅读成员对象和基类子对象的构造和销毁顺序。


术语

  • 覆盖函数意味着在派生类中实现基类virtual 函数。您根本无法更改签名(使用协变返回类型除外)。因此,override 总是与继承的虚函数具有相同的签名。
  • 重载一个函数意味着实现多个同名的函数(在某种意义上是相同的作用域)。因此,重载总是与其他同名的不同签名,与虚拟调度没有直接关系,也不一定是继承的。

【讨论】:

  • 不需要虚拟子析构函数,因为派生类“继承”了父类的虚拟方面。 reference
  • 关键字“virtual”不是必须的,是的,这是我写的Grandchild类来说明的。虽然它仍然是一个虚拟析构函数,所以我不确定你想说什么。
  • 是的,我只是说 Child 类的“virtual”关键字不是必需的。 Child 和 Grandchild 都已经是虚拟的(就像您为 Grandchild 绘制的插图一样)。
【解决方案2】:

我可能对单词的语法感到困惑

不,你绝对不是——这是两个截然不同的东西。

但是是否可以覆盖析构函数?

是的,事实上你必须在很多情况下这样做。为了使这适用于多态对象,您需要将基类析构函数声明为 virtual,不过:

Parent const& p = Child();

将在作用域结束时正确调用 p.~Child(),因为 Parent::~Parent 是虚拟的。

【讨论】:

  • @yngum 啊。显然是“析构函数”。
  • 虚拟构造函数不存在。而且你甚至不能在构造函数中调用虚方法。
  • @KonradRudolph 但这能回答问题吗?我希望 Child 重新定义对 ~Parent() 的调用。
  • @DannyA 很遗憾你不能,每个类只能有一个析构函数定义。
  • @PhilipStuyck - 你当然可以在构造函数中调用虚函数。该调用转到当前正在构造的类,该类不一定是派生最多的类。
【解决方案3】:

是的;每当您有一个可以使用对基类的引用来销毁的子类时,您都可以并且应该使析构函数成为虚拟的。如果您提供虚拟析构函数,静态代码分析工具甚至会报错。

考虑以下示例:

class A
{
public:
    A() { a = new int; }
    virtual ~A() { delete a; }

private:
    int *a;
};

class B : public A
{
public:
    B() { b = new int; }
    virtual ~B() { delete b; }

private:
    int *b;
};

int main()
{
    A *a = new B();
    delete a;
}

如果析构函数不是虚拟的,那么delete a 只会调用A 的析构函数,最终会导致内存泄漏。但是因为它是虚拟的,所以两个析构函数都会被调用,顺序是~B() -> ~A()

【讨论】:

    【解决方案4】:

    是的,可以覆盖类的析构函数。事实上,当您定义一个使用多态性的类层次结构时,您必须在基类中声明一个虚拟析构函数。

    析构函数重写的工作方式与普通成员函数的重写完全相同,因为当您通过指向基类的指针deleteing 对象来销毁对象时,派生类的析构函数会被正确调用。这就是为什么在多态层次结构的基类中必须有一个虚拟析构函数。

    然而,虚析构函数和虚成员方法之间是有区别的,这与析构函数的virtual性质无关。也就是说,当执行这样的代码时:

    class A
    {
    public:  
      virtual void Foo() {}
      virtual ~A() {};
    };
    
    class B : public A
    {
    public:
      void Foo() {};
      ~B() {}
    };
    
    int main()
    {
      A* a = new B;
      a->Foo();  // B::Foo() is called
      delete a;  // B is destroyed via B::~B()
    }
    

    ...当你调用a->Foo()时,会调用B中的方法Foo()。由于B::Foo() 没有显式调用A::Foo(),因此不会调用A::Foo()

    但是,当对象通过delete a;销毁时,首先调用析构函数B::~B(),然后在完成之后但在控制返回程序之前,基类析构函数A::~A()也是 /em> 调用。

    当然,当您考虑它时,这是显而易见的,这与析构函数的 virtual 本质无关,但它的行为确实与普通的 virtual 方法调用不同,所以我想我'请指出来。

    强制性标准报价:

    [C++03] 12.4/6 : 析构函数

    在执行析构函数的主体并销毁任何 在主体内分配的自动对象,类 X 的析构函数 为 X 的直接成员调用析构函数,为 X 的直接成员调用析构函数 直接基类,如果 X 是最派生类的类型 (12.6.2),它的析构函数调用 X 的虚基的析构函数 类。所有的析构函数都被调用,就好像它们被一个限定名引用一样,也就是说,忽略任何可能的虚 在更多派生类中重写析构函数。基地和成员是 以完成它们的相反顺序销毁 构造函数(见 12.6.2)。析构函数中的 return 语句 (6.6.3) 可能不会直接返回给调用者;在转移控制权之前 对于调用者,成员和基的析构函数被调用。 数组元素的析构函数以相反的顺序调用 它们的构造(见 12.6)。

    【讨论】:

      猜你喜欢
      • 2013-08-27
      • 2016-11-26
      • 2016-08-14
      • 2018-10-30
      • 1970-01-01
      • 1970-01-01
      • 2015-03-24
      • 1970-01-01
      • 2012-07-28
      相关资源
      最近更新 更多