纯抽象基类中的虚拟析构函数

Posted

技术标签:

【中文标题】纯抽象基类中的虚拟析构函数【英文标题】:virtual desctructor on pure abstract base class 【发布时间】:2011-03-21 04:09:13 【问题描述】:

我有

struct IMyInterface

   virtual method1() = 0;
   virtual method2() = 0;
;

GCC 坚持我有

struct IMyInterface

   virtual method1() = 0;
   virtual method2() = 0;
   virtual ~IMyInterface();
;

我不明白为什么。纯粹的界面就是界面(duh)。析构函数是接口具体实现者内部实现细节的一部分;它不构成接口的一部分。我了解整个切片问题(或者至少我认为我了解)

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

【问题讨论】:

您在谈论析构函数,但您的代码显示了一个构造函数。问题是什么? 编程规则 1:编译器永远是对的。编程规则 2:如果编译器错误,则适用规则 1。 你可以有一个纯虚析构函数 (virtual ~IMyInterface() = 0;) 但如果链接器抱怨缺少定义,你实际上仍然可以提供纯虚函数的实现,即。 virtual ~IMyInterface() = 0 . 【参考方案1】:

根据 C++ 规范,是的。

你需要将析构函数声明为虚拟的,否则,稍后

    IMyInterface * ptr = getARealOne();
    delete ptr;

不会在派生类上调用析构函数(因为析构函数不在 VTable 中)

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

为了进一步解释,C++ 没有像 Java 或 C# 那样的接口概念。仅使用纯虚拟方法只是一种约定,并将其视为接口。关于 C++ 析构函数的其他规则使其必须是非纯的,这破坏了与其他语言中接口的相似性,但这些语言在制定这些规则时并不存在。

【讨论】:

Nitpick - 如果您想要求子类来实现它,我认为您可以将其设为纯虚拟。但是由于您所说的原因,您仍然必须提供一个实现。 我不这么认为——它会被调用,所以最好有一个定义。我还没有尝试过,但通常编译器会实现纯虚拟,因为在 VTable 中放置一个错误函数来抱怨它被调用了。也许我可以想象析构函数的特殊情况,但我很确定这不是规范所说的(虽然不是 100%) @Lou Franco:纯虚函数可以有定义。 @Lou:“纯”并不意味着它没有定义,只是它必须被覆盖。析构函数可以是纯的也可以不是,但必须有定义。 是的——对不起,是的。不是他的做法(在声明时)。【参考方案2】:

如果你没有在基类中声明 virtual d'tor,通过指向基类的指针删除派生类的对象会导致调用错误的析构函数,从而导致未定义的行为和资源泄漏。

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.

【讨论】:

Nitpick:B::us_constitution 不能被释放,因为它从来都不是新的。但是,如果没有虚拟析构函数,它使用的存储将不会返回到系统。

以上是关于纯抽象基类中的虚拟析构函数的主要内容,如果未能解决你的问题,请参考以下文章

C++中的各种“虚“-- 虚函数纯虚函数虚继承虚基类虚析构纯虚析构抽象类讲解

关于纯虚析构函数的问题

虚函数构造和析构函数执行顺序总结

错误 LNK2019 - 抽象类中的虚拟析构函数 [重复]

为啥我们需要 C++ 中的纯虚析构函数?

为多态基类声明一个虚析构函数