【问题标题】:virtual destructor for pure abstract class [duplicate]纯抽象类的虚拟析构函数[重复]
【发布时间】:2019-12-08 01:46:10
【问题描述】:

根据我发现的here 和stackoverflow 上的其他链接,如果我们打算以多态方式使用它,我们应该始终在基类中定义一个虚拟析构函数。我想知道这条规则是否有例外。

我已经看到没有为纯抽象基类定义虚拟析构函数的生产代码,并且在 cppcon 2014 视频Accept no visitor 之一中,大约 10:06 定义的 BoolExp 结构是纯抽象类并且没有虚拟析构函数。

所以对于这样定义的纯抽象类

  class Base {
      public:
         virtual foo() = 0;
         virtual bar() = 0;
     }

我的问题是我们绝对必须为“Base”类定义一个虚拟析构函数,即使它确实有任何数据成员?虚拟析构函数规则是否有任何例外?

提前致谢。

最好, RG

【问题讨论】:

  • 可以,但不推荐。如果对象的生命周期不是由指向基类的指针管理的,则不需要这样做,但无论如何我都会这样做。
  • 如果要多态地删除,则需要一个虚拟析构函数。见stackoverflow.com/q/461203/10077
  • 可能是为了节省空间而从幻灯片中删除。
  • 嗯。一定是这样的。感谢您的帮助

标签: c++ abstract-class virtual-destructor


【解决方案1】:

使用指向具有非虚拟析构函数的基类的指针删除派生类对象会导致未定义的行为。

否则你可以不用虚拟析构函数。

【讨论】:

    【解决方案2】:

    该规则的例外是,如果您从不通过指向基类的指针删除对象。在这种情况下,基类析构函数不需要是virtual

    但是如果你曾经通过基类指针删除一个对象,那么基类析构函数必须virtual 或者你的程序有未定义的行为。

    【讨论】:

      【解决方案3】:

      我们是否必须为“Base”类定义一个虚拟析构函数,即使它确实有任何数据成员?虚拟析构函数规则是否有任何例外?

      这不是必须。这是一个可以防止错误的好习惯。

      如果您决定创建一个没有虚拟析构函数的基类,则开发人员有责任始终确保派生对象被删除为正确的类型或作为确实具有虚拟析构函数的基类型。

      【讨论】:

        【解决方案4】:

        我的问题是我们绝对必须为“Base”类定义一个虚拟析构函数,即使它确实有任何数据成员?

        严格来说,没有。

        然而,基类是否有任何成员变量并不相关。如果使用指向基类的指针调用析构函数,则无论基类是否有任何成员变量,您的代码都会有未定义的行为。

        虚拟析构函数规则有什么例外吗?

        如果您能够管理派生类的生命周期,即通过派生类指针调用 delete 对象,则您不会调用未定义的行为,并且您的代码将表现良好,假设一切正常else 在您的代码库中处于良好状态。

        【讨论】:

          【解决方案5】:

          我的问题是我们绝对必须为“Base”类定义一个虚拟析构函数,即使它确实有任何数据成员?

          这取决于。如果你有这样的情况

          base * foo = new child(stuff);
          // doing stuff
          delete foo;
          

          那么你绝对必须有一个虚拟析构函数。没有它,您将永远无法破坏 child 部分。

          如果你有这样的情况

          child * foo = new child(stuff);
          // doing stuff
          delete foo;
          

          那么你就不需要虚拟析构函数了,因为child's 会被调用。

          所以规则是如果你多态删除,你需要一个多态(虚拟)析构函数,如果没有,那么你不需要

          【讨论】:

            【解决方案6】:

            我想对描述通过基础对象删除的正确答案进行重要的(至少在我看来)实际修改。

            特别是,如果对象生命周期是通过分配的std::shared_ptr<Base> 管理的,则非虚拟调用析构函数

            std::shared_ptr<Base> sptr = std::make_shared<Derived>(args);
            

            【讨论】:

            • 我们在工作中遇到了问题,将std::shared_ptr 提升为std::unique_ptr,类缺少虚拟析构函数......
            • @Jarod42 我称之为“降级”。但我理解你。
            【解决方案7】:

            如果我们打算多态地使用它,我们应该总是在基类中定义一个虚拟析构函数。

            如果我们打算通过该基类以多态方式删除它,您应该始终在基类中定义一个虚拟析构函数。

            现在,一个问题是“我不打算”是不安全的;你应该让它变得不可能。

            将析构函数设为虚拟(且为空),将其设为受保护(且为空)。受保护的析构函数使得多态删除不太可能(它可以被绕过,但只能通过非常疯狂的方式)。

            除此之外,您必须小心。这就是为什么从(比如说)std vector 继承是一件需要警惕的事情的原因之一。

            【讨论】:

              猜你喜欢
              • 2019-04-20
              • 2011-03-21
              • 2011-03-31
              • 1970-01-01
              • 2011-05-21
              • 1970-01-01
              • 2023-03-23
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多