纯虚基类上的虚析构函数

14

我有一个问题

struct IMyInterface
{
   virtual method1() = 0;
   virtual method2() = 0;
};

GCC坚持认为我有

struct IMyInterface
{
   virtual method1() = 0;
   virtual method2() = 0;
   virtual ~IMyInterface(){};
};

我不明白为什么。纯接口完全与接口有关(显然)。析构函数是接口的具体实现者的内部实现细节的一部分;它不构成接口的一部分。我理解整个切割问题(或者至少我认为我理解了)。

所以我的问题是 - GCC是否正确坚持这样做,如果是为什么?


你在谈论析构函数,但你的代码展示的是构造函数。这个问题是关于哪个的? - Michael Myers
1
编程规则1:编译器永远是正确的。编程规则2:如果编译器错了,适用规则1。 - Brian Hooper
你可以拥有一个纯虚析构函数(virtual ~IMyInterface() = 0;),但如果链接器抱怨缺少定义,你实际上仍然可以为纯虚函数提供实现,即virtual ~IMyInterface() = 0 {} - AshleysBrain
2个回答

25
根据C++规范,是的。您需要声明析构函数为虚拟的,否则稍后...
    IMyInterface * ptr = getARealOne();
    delete ptr;

由于析构函数不在VTable中,因此不会调用派生类的析构函数。

它需要是非纯的,因为基类析构函数总是由子类析构函数调用。

进一步解释一下,C++并没有像Java或C#那样的接口概念。仅仅是一种惯例,使用纯虚函数,并将其视为接口。C++析构函数的其他规则使得它需要是非纯的,这打破了与其他语言中接口的相似性,但这些规则是在这些语言出现之前制定的。


4
如果你想要子类实现它,我认为你可以将其设为纯虚函数。但是,如你所述,你仍需要提供一个实现。 - Michael Kristofik
我不这么认为——如果它被调用,那么最好有一个定义。虽然我没有尝试过,但通常纯虚函数会被编译器实现为在VTable中放置一个错误函数来抱怨它被调用了。也许我可以想象析构函数的特殊情况,但我很确定规范并不是这样说的(虽然不是100%确定)。 - Lou Franco
@Lou Franco:纯虚函数可以有定义。 - Billy ONeal
@Lou:“纯虚”并不意味着它没有定义,只是必须被覆盖。析构函数可以是纯虚的或非纯虚的,但必须有一个定义。 - Mike Seymour
是的 - 对不起,那是正确的。他现在这样做是不对的(在声明的时候)。 - Lou Franco
这是规范讨论的相关部分 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#230 - Lou Franco

3
如果在基类中不声明虚拟析构函数,则通过指向基类的指针删除派生类对象会导致调用错误的析构函数,从而导致未定义行为和资源泄漏。
struct A {

  virtual ~A() {}

};

struct B : A {

   std::string us_constitution;  
};


B* pb = new B();
A* pa = pb;

delete pa; // without the virtual d'tor in the base class, 'B::us_constitution' would never be freed.

小问题:B::us_constitution无法被释放,因为它从未被new过。然而,它使用的存储空间如果没有虚析构函数将不会返回给系统。 - Billy ONeal

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