纯抽象基类中的虚拟析构函数
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 不能被释放,因为它从来都不是新的。但是,如果没有虚拟析构函数,它使用的存储将不会返回到系统。以上是关于纯抽象基类中的虚拟析构函数的主要内容,如果未能解决你的问题,请参考以下文章