首页 > 解决方案 > 重写析构函数 - C++

问题描述

假设我有:

struct Base
{
    /**/ virtual /**/ ~Base() {/*..*/}
    // ...
};

struct Derived : Base
{
    ~Derived() /* override */ {/*..*/}
    // ...
};

当一个类从另一个类继承时,重写是为了帮助我确保我正在实现一个实际存在于Base. 在上述场景中,Derived类的名称与 不同Base,因此其析构函数的编写方式也不同。

我的问题是,如果我想使用override,我应该在哪里使用它?我在 Derived 类中真正在哪里实现 aBase的函数?

标签: c++

解决方案


首先,“覆盖”关键字仅表示“此函数在某些基类中被标记为虚拟”,仅此而已。它也可以应用于析构函数。然而,析构函数是特殊的,一般规则不适用于它们。例如 destructor in Derived, named~Derived()与 destructor in Base, named相匹配~Base(),尽管它们在形式上具有不同的名称(或者它们是什么?这里的名称是什么?)。

析构函数和典型函数之间的另一个区别是析构函数总是在继承链中调用,而不管实现如何。所以你不能“取代”破坏,你只能“扩展”它。请注意(与普通函数不同)从派生析构函数调用基类析构函数是错误的。

链式销毁调用从您当前引用的类开始。我的意思是

Base* inst = new Derived();
delete inst;

将调用~Base(),因为变量instBase*即使它是从派生类构造的。此时“虚拟逻辑”适用:如果~Base()不是虚拟的,则为Base类触发正常的销毁过程,而不知道实际的对象是Derived*,即~Base(),它的所有父描述符(在这种特殊情况下没有)被执行。这是错误的。但如果它是虚拟的,那么它实际上会跳转到正确的类,,Derived并调用正确的销毁过程:首先~Derived(),然后~Base()看到这个godbolt.org并玩转:在基本析构函数中添加和删除“虚拟”以查看差异(仅查看左列,带有彩色背景的行是实际调用的行)。

总而言之:是的,您可以使用~Derived() override {}. 我总是在适当的地方使用“覆盖”,很高兴知道哪些函数是从虚函数派生的。经验法则是:如果Base是虚拟的(意味着任何函数都是虚拟的),那么它的析构函数也应该是虚拟的。记住这一点,它将帮助您避免一些问题。


推荐阅读