默认虚拟析构函数

8

假设我有两个类:

class Base{};

class Derived: public Base{};

在这种情况下,如果我声明了关于变量的内容,那么就没有d'tor(析构函数)。

Base b;
Derived d;

我的编译器将为我生成析构函数,我的问题是,bd的默认析构函数是否是虚拟的?


可能是C++中虚默认析构函数的重复问题的副本。 - Roger Pate
6个回答

8
我的问题是,b和d的析构函数是否为虚函数?
不是。如果你想要一个虚析构函数,你需要自己定义,即使它的实现与编译器提供的完全相同。
class Base {
  public:
    virtual ~Base() {}
};

7

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!祝好运!

2
@Armen:shared_ptr 知道静态类型是 Concrete。这是因为我在构造函数中传递了它!看起来有点像魔法,但我可以向你保证这是设计得非常好的。 - Daniel Lidström
2
@Oli:当您递归应用RAII时,始终使用shared_ptr,其效果是突然间您实际上根本不需要析构函数! shared_ptr可以包装任何资源,并且当您可以使用新的lambda语法指定自定义删除器时,它甚至更加方便。 - Daniel Lidström
7
我认为,暗示多态基类只应该有虚析构函数以消除警告是错误的建议。对于一个被设计为继承层次结构通用基类的类而言,不提供虚析构函数将强制用户使用shared_ptr或等效物。那些不试图管理如何被使用的类更加灵活。给这样的类一个虚析构函数可以在几乎没有额外成本的情况下使它在更多的情况下被正确使用。在这种情况下,用户通常不会收到任何关于不正确使用的警告。类应该尽可能地易于正确使用。 - CB Bailey
2
@Charles:你说得对。由于我无法监督OP的工作,我不知道他是否遵循要求。因此,我的建议对于初学者来说并不是真正合适的。如果他和我一起工作,我会引导他走向设计模式的道路。任何接口层次结构都需要使用抽象工厂。然而,这是一个我不想在这里讨论的话题。 - Daniel Lidström
2
@Tomaka17:你说得对,Base* pBase = new Concrete; shared_ptr<Base> shpBase(pBase); 是危险的,但这也是Daniel想表达的一部分。他只是想说 shared_ptr<Base> shpBase(new Concrete); 不危险,因为有 shared_ptr 的构造函数模板。 - CB Bailey
显示剩余12条评论

5
我的问题是,b和d的文档是否是虚拟的?
简短回答:不是!

3

它们不会是虚拟的。然而,如果你在基类中声明(和定义)了一个虚拟析构函数,那么派生类的析构函数将自动成为虚拟函数。希望这有帮助。


1

只是为Daniel Lidström的回答增加一个例子

只要您始终将分配的对象存储在shared_ptr中,那么您就不需要虚析构函数。

如果使用shared_ptr如下:

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

在对象销毁时,Concrete析构函数和Base析构函数将被调用。
如果使用shared_ptr,可以这样:
Base* pBase = new Concrete;
std::shared_ptr<Base> b(pBase);

销毁对象时仅调用基类析构函数。
这是一个例子
#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;
  }

}

1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接