【问题标题】:default virtual d'tor默认虚拟导师
【发布时间】:2011-04-23 10:00:17
【问题描述】:

假设我有两个类:

class Base{};

class Derived: public Base{};

没有 d'tor,在这种情况下,如果我声明变量:

Base b;
Derived d;

我的编译器会为我生成 d'tors,我的问题是,b and d 的默认 d'tors 是否是虚拟的?

【问题讨论】:

标签: c++ destructor


【解决方案1】:

我的问题是,b 和 d 的 d'tors 是否是虚拟的

不,他们不会。如果你想要一个虚拟析构函数,你必须定义你自己的,即使它的实现与编译器提供的完全一样:

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

【讨论】:

    【解决方案2】:

    BaseDerived 的析构函数不会是 virtual。要创建 virtual 析构函数,您需要明确标记它:

    struct Base
    {
        virtual ~Base() {}
    };
    

    实际上,现在使用虚拟析构函数只有一个原因。那就是关闭gcc警告:“类'Base'具有虚函数但非虚析构函数”。只要您始终将分配的对象存储在shared_ptr 中,那么您就真的不需要虚拟析构函数。方法如下:

    #include <iostream>   // cout, endl
    #include <memory>     // shared_ptr
    #include <string>     // string
    
    struct Base
    {
       virtual std::string GetName() const = 0;
    };
    
    class Concrete : public Base
    {
       std::string GetName() const
       {
          return "Concrete";
       }
    };
    
    int main()
    {
       std::shared_ptr<Base> b(new Concrete);
       std::cout << b->GetName() << std::endl;
    }
    

    shared_ptr 将正确清理,无需虚拟析构函数。请记住,您需要使用shared_ptr

    祝你好运!

    【讨论】:

    • @Armen:shared_ptr 知道静态类型是具体的。它知道这一点,因为我在它的构造函数中传递了它!看起来有点像魔术,但我可以向你保证,这是设计使然,非常好。
    • @Oli:当你递归应用 RAII 时,总是使用 shared_ptr,效果是突然间你根本不需要析构函数了! shared_ptr 可以包装任何资源,如果您可以使用新的 lambda 语法指定自定义删除器,则更加方便。
    • 我认为暗示多态基类应该具有虚拟析构函数只是为了消除警告是一个糟糕的建议。不为设计为继承层次结构的公共基类的类提供虚拟析构函数会强制用户使用shared_ptr 或等效项。不尝试管理它们的使用方式的类更加通用。为这样的类提供一个虚拟析构函数可以在更多情况下正确使用它,而无需额外的成本。在这种情况下,用户通常不会收到有关错误使用的警告。类应该易于正确使用。
    • @Charles:你是对的。由于我无法监督 OP 的工作,我不知道他是否遵守要求。所以我的建议并不适合初学者。如果他和我一起工作,我会带领他走上设计模式的道路。任何接口层次结构都需要使用抽象工厂。但是,这是我不想在这里进行的讨论。
    • @Tomaka17:你说Base* pBase = new Concrete; shared_ptr&lt;Base&gt; shpBase(pBase); 很危险是对的,但这是丹尼尔的观点的一部分。他只是说shared_ptr&lt;Base&gt; shpBase(new Concrete); 并不危险,但事实并非如此,因为shared_ptr 的构造函数模板。
    【解决方案3】:

    我的问题是,b 和 d 的 d'tors 是否是虚拟的

    简短回答:不!

    【讨论】:

      【解决方案4】:

      它们不会是虚拟的。但是,如果您在 Base 中声明(并定义)了一个虚拟 dtor,那么派生的 dtor 将自动是虚拟的。 HTH。

      【讨论】:

        【解决方案5】:

        除非你明确地将它们设为虚拟,否则它们怎么可能是虚拟的

        【讨论】:

          【解决方案6】:

          只是为了给Daniel Lidström's answer添加一个例子

          As long as you always store your allocated objects in a shared_ptr, then you really don't need a virtual destructor.

          如果有人像这样使用 shared_ptr:

              std::shared_ptr<Base> b(new Concrete);
          

          然后在销毁对象时调用具体析构函数和基础析构函数。

          如果有人像这样使用 shared_ptr:

          Base* pBase = new Concrete;
          std::shared_ptr<Base> b(pBase);
          

          然后在销毁对象时只调用 Base 析构函数。

          这是an example

          #include <iostream>   // cout, endl
          #include <memory>     // shared_ptr
          #include <string>     // string
          
          struct Base
          {
             virtual std::string GetName() const = 0;
             ~Base() { std::cout << "~Base\n"; } 
          };
          
          struct Concrete : public Base
          {
             std::string GetName() const
             {
                return "Concrete";
             }
             ~Concrete() { std::cout << "~Concrete\n"; } 
          };
          
          int main()
          {
            {
              std::cout << "test 1\n";
              std::shared_ptr<Base> b(new Concrete);
              std::cout << b->GetName() << std::endl;
            }
          
            {
              std::cout << "test 2\n";
              Base* pBase = new Concrete;
              std::shared_ptr<Base> b(pBase);
              std::cout << b->GetName() << std::endl;
            }
          
          }
          

          【讨论】:

            猜你喜欢
            • 2011-07-22
            • 2017-01-26
            • 1970-01-01
            • 2019-05-05
            • 1970-01-01
            • 2012-10-15
            • 2013-03-24
            • 2016-04-29
            • 1970-01-01
            相关资源
            最近更新 更多