[英]C++11 interface pure virtual destructor
UPD 。 有一个标记,它是这个问题的副本。 但是在那个问题上,OP问如何使用default
来定义纯虚析构函数。 这个问题是关于有什么区别的 。
在C ++(如果可能的话,最新标准)中,使用空体实现定义纯虚拟析构函数和仅使用空体(或默认值)之间的真正区别是什么?
变式1:
class I1 {
public:
virtual ~I1() {}
};
变式2.1:
class I21 {
public:
virtual ~I21() = 0;
};
I21::~I21() {}
变式2.2:
class I22 {
public:
virtual ~I22() = 0;
};
I22::~I22() = default;
更新我发现Variant 1和Variants 2.1 / 2.2之间至少有1个区别:
对于Variant 1, std::is_abstract::value
为false
,对于Variants 2.1和2.2,则为true
。
可能有人可以发现2.1和2.2之间的区别?
正如您所指出的,I1和I2 *之间的区别在于,添加= 0
会使类抽象化。 事实上,当你没有任何其他函数是纯虚拟时,使析构函数成为虚拟是一个使类抽象的技巧 。 我说这是一个技巧,因为如果你想要破坏析构函数的任何派生类(在这里你会),析构函数不能保持未定义,那么你仍然需要定义析构函数,无论是空的还是默认的。
现在,空的或默认的析构函数/构造函数(I21和I22)之间的区别更加模糊,没有太多的写入。 推荐的是使用default
,作为一种新的习惯用语,使你的意图更清晰,显然,给编译器一个优化的机会。 引用msdn
由于普通特殊成员函数的性能优势,我们建议您在需要默认行为时更喜欢在空函数体上自动生成特殊成员函数。
除了可能的性能改进之外,两者之间没有明显的差异。 = default
是从C ++ 11开始的方式。
我能找到的只有:
§12.4(5.9)
析构函数可以声明为虚拟(10.3)或纯虚拟(10.4); 如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。 如果类具有带虚拟析构函数的基类,则其析构函数(无论是用户还是隐式声明)都是虚拟的。
导致:
§10.4(该类现在是抽象的)
10.4(2)说:
只有在使用(12.4)qualified-id语法(5.1)调用时,才需要定义纯虚函数。
但是关于§12.4中的析构函数的叙述谈到了析构函数总是被称为完全限定名称(为了防止歧义)。
意思就是:
必须定义析构函数,即使是纯虚拟的,也是如此
这个班级现在是抽象的。
变体1将允许您拥有该类的实例。 变体2.1,2.2不允许实例,但允许后代的实例。 例如,这可以工作(并且能够让许多人感到困惑),而删除标记的行会使编译失败:
class I21 {
public:
virtual ~I21() = 0;
};
I21::~I21() {} // remove this and it'll not compile
class I22 : public I21
{
public:
virtual ~I22() {}
};
int main() {
I22 i;
return 0;
}
后面的原因,析构函数链直接调用I21 ::〜I21()而不是通过接口。 也就是说,目前尚不清楚纯虚拟析构器的目标是什么。 如果您想避免实例化(即静态类),您可以考虑删除构造函数; 如果你想要可以实例化但不是这个类的后代,也许你需要一个在后代中实现的纯虚拟成员函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.