提供一个纯虚析构函数:
struct Base {
virtual ~Base() = 0;
};
inline Base::~Base() {}
您需要提供一个实现,您可以通过将其设置在标题中inline
。
抽象类是具有一些纯虚函数的类:
[...]一个类是抽象的,如果它至少有一个纯虚函数。[...]
[N4431 §10.4/2]
由于您想要一个指向抽象类(派生自)实例的指针数组,我假设您还希望最终能够delete
通过这些指针破坏这些实例中的一个或多个:
Base * instance = // ... whatever ...
delete instance;
在这种情况下,要调用正确的析构函数(派生类的),析构函数必须是虚拟的。
因此,由于无论哪种方式它都是虚拟的,并且您不想要一些纯虚拟成员函数,因此最好将析构函数设为纯虚拟。
要使虚函数成为纯函数,请将纯说明符附加到其声明中:
struct Foo {
virtual void bar(void) /* the */ = 0; // pure-specifier
};
现在,关于定义,你想知道为什么我们需要提供一个,因为......
[...] 纯虚函数仅在使用或如同使用 (12.4) 限定 ID 语法 (5.1) 调用时才需要定义。[...]
[N4431 §10.4/2]
这是因为在析构派生类时,在调用派生类析构函数后,基类的析构函数也会被调用:
struct Derived : public Base {
~Derived() {
// contents
// Base::~Base() will be called
}
};
在执行析构函数的主体后 [...] 类 X 的析构函数调用 [...] X 的直接基类的析构函数,如果 X 是最派生类 (12.6.2) 的类型,则调用它的析构函数调用 X 的虚拟基类的析构函数。所有的析构函数都被调用,就好像它们是用限定名称引用的一样 [...]
[N4431 §12.4/8]
Base
因此,如果需要该类,则定义纯虚拟析构函数。然而 ...
[...] 函数声明不能同时提供纯说明符和定义 [...]
[N4431 §10.4/2]
...所以它必须在类定义之外定义。这可以在单独的源文件中完成,或者感谢...
内联函数应在使用 odr 的每个翻译单元中定义,并且在每种情况下都应具有完全相同的定义 [...]
[N4431 §7.1.2/4]
...作为inline
标题中的函数。
在这种情况下,该标准甚至明确规定了定义的要求:
析构函数可以声明为虚拟(10.3)或纯虚拟(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。[...]
[N4431 §12.4/9]