C++ 为什么可以';我是否声明了一个纯虚函数,其“=delete;”? 简介

C++ 为什么可以';我是否声明了一个纯虚函数,其“=delete;”? 简介,c++,c++11,C++,C++11,纯虚拟函数采用通用语法: virtual f() = 0; 然而,自c++11以来,有一种方法可以传达(特殊)成员函数的显式不存在: Mystruct() = delete; // eg default constructor Q 为什么不将此语法扩展到纯虚拟函数,以实现此类操作通信的一致性 virtual f() = delete; 注 我知道最明显的答案是,因为标准是这么说的。我想知道这背后的原因,以及是否有过类似的提议(或意图) =删除意味着完全不同于使函数成为纯虚拟函数。与已删

纯虚拟函数采用通用语法:

virtual f() = 0; 
然而,自c++11以来,有一种方法可以传达(特殊)成员函数的显式
不存在

Mystruct() = delete; // eg default constructor
Q 为什么不将此语法扩展到纯虚拟函数,以实现此类操作通信的一致性

virtual f() = delete; 

我知道最明显的答案是
,因为标准是这么说的。我想知道这背后的原因,以及是否有过类似的提议(或意图)

=删除意味着完全不同于使函数成为纯虚拟函数。与已删除的函数不同,纯虚拟函数不会使程序因重载解析而选择格式错误的函数。

这两者的含义有很大的不同。粗略地说,区别在于:

virtual void f() = 0; 
virtual void f() = 0; 
表示“我还没有编写此函数的实现。”

然而,这:

f() = delete;

表示“注意编译器:不要创建此函数的实现。”

粗略地说,区别在于:

virtual void f() = 0; 
virtual void f() = 0; 
表示“这个类是抽象的,我可能还没有编写这个成员函数的实现”(尽管允许您这样做)

然而,这:

void f() = delete;

表示“此成员函数实际上不存在,且任何成员函数都不会通过。”

有一些自动生成的成员函数:默认构造函数、析构函数、复制构造函数、赋值,还有一些新的移动构造函数

能够
删除它们的目的是确保编译器不允许调用它们。老把戏是将它们声明为私有,而不是给它们一个实现

这样做很麻烦,但值得注意的是,它并没有完全阻止调用它们,因为友元类(甚至类本身)可能会意外调用副本或赋值,而且尽管会出现链接器错误,但这并不理想,因为您看不到错误所在,并且确实希望出现编译器错误


将函数声明为虚拟且
=0
不会阻止调用该函数。它在使类抽象从而无法创建实例方面有着特殊的意义,这意味着该函数不需要实现,但它与删除它有着不同的意义。

virtual~MyStruct()=delete
已经被采用了,并且表现得非常不同。@chris Yep,强项。即使有这样的意图,也无法实现。
=delete
已经被允许用于非特殊成员函数(包括虚拟函数)和非成员函数,并且意味着“调用此函数是编译时错误”。请记住,语法
virtual f()=0
也没有任何推理依据。根据Bjarne Stroustrup的说法,他认为没有机会在时间上接受一个新的关键字严格地说,
virtual f()=0
实际上无法编译,因为我们不能有一个纯虚拟构造函数。它必须在某个地方有一个类型才能不是构造函数。后者说的更多!它还说,“如果你发现我试图使用这个,惩罚我,因为我是一个非常淘气的男孩”。@R.MartinhoFernandes,你又裸体了吗?前者根本不是这个意思。为纯虚函数生成定义是完全有效的。真相见我的答案。@LightnessRacesinOrbit:目的是传达一个粗略的近似值,以帮助理解,而不是引用《标准》中的章节。话虽如此,我还是很喜欢R.Martinho Fernandes对
删除
的解释@Edward:好吧,如果你说的“传达一个粗略的近似值”真的是指“传播一个危险和流行的误解”,那么你做得很好!相反,讲真话有助于理解;通过说出非事实事实,你实际上伤害了理解力(这应该是不言而喻的)。
不会使选择它的程序格式错误
,因为不可能有抽象类的实例,在重载解析后,绝对不能选择纯虚函数
抽象类*a=新派生类;a->pure_virtual_函数()
@R.MartinhoFernandes我认为重载解析不会选择基类的
纯虚拟函数()
。@R.MartinhoFernandes这个例子正是我的意思。是否将动态调度视为过载解决后的一个步骤?因为从高层次上讲,总是选择派生类中的实现。@NikosAthanasiou:动态调度发生在运行时,基于当时实际使用的对象。重载解析发生在编译时。我从未使用过这种
delete
符号,我很好奇它与不定义函数相比有什么好处。有什么建议吗?@Logicrat:这对复制构造函数等很有用。如果您只是不声明副本构造函数,那么在某些/许多情况下,会为您声明一个副本构造函数。您必须将其标记为
private
,以防止使用它,然后编译错误就不那么清楚了<代码>=删除
记录意图并改进诊断。