【问题标题】: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 {}.

标签: c++ virtual-destructor


【解决方案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 不能被释放,因为它从来都不是新的。但是,如果没有虚拟析构函数,它使用的存储将不会返回到系统。
猜你喜欢
  • 2019-04-20
  • 2019-12-08
  • 2023-03-23
  • 2011-03-31
  • 1970-01-01
  • 1970-01-01
  • 2014-02-23
  • 2018-07-20
  • 1970-01-01
相关资源
最近更新 更多