为什么纯虚函数要用0进行初始化?

169

我们总是将纯虚函数声明为:

virtual void fun () = 0 ;

也就是说,它总是被赋值为0。

我的理解是,这是将此函数的虚函数表入口初始化为NULL,而在这里使用任何其他值都会导致编译时错误。我的理解是否正确?


18
请注意,虚函数表并不是语言要求,而只是一种实现虚函数的选项。编译器可以使用不同的实现方式来创建相同的抽象,即不使用虚函数表,也不让其中的任何元素为0。 - David Rodríguez - dribeas
关于您的补充问题 - 这是我的答案(以及其他几个人)所说的。 - anon
1
好奇一下,如果我这样写:virtual void func() = 100;会发生什么? - krithikaGopalakrishnan
11个回答

177

使用=0的原因是Bjarne Stroustrup当时认为他无法获得另一个关键字,例如“pure”,通过C++社区来实现该功能。这在他的书The Design & Evolution of C++第13.2.3节中有描述:

选择好奇的=0语法的原因是... 因为当时我看不到 获得新关键字的机会。

他还明确指出,这不需要将vtable条目设置为NULL,并且这样做并不是实现纯虚函数的最佳方法。


5
没错,这只是语法。我见过很多项目都会 #define PURE =0,然后在声明中使用 virtual void Foo() PURE;。 - i_am_jorf
83
请上帝将我远离那些项目 :-) - anon
28
这比 #define BEGIN { #define END } 好很多了,我有时也看到过这种写法。 - Toon Krijthe
5
这种巧妙的东西让我觉得C++不够完善。考虑到它被如此广泛地使用,这很奇怪。希望随着时间的推移,这门语言能变得更好。 - jokoon
22
换句话说,Bjarne "面临着最后期限",并使用了一个"hack"来克服"设计缺陷" ;)(只是开玩笑) - Carl
显示剩余5条评论

86
与大多数关于C ++设计的“为什么”问题一样,首先要查看的地方是Bjarne Stroustrup的《C ++设计与演化》1

选择奇怪的=0语法而不是引入新的关键字pureabstract的显而易见的替代方案,因为我当时认为没有机会让新的关键字被接受。如果我建议pure,Release 2.0将在没有抽象类的情况下发货。在优雅的语法和抽象类之间做出选择,我选择了抽象类。我使用传统的C和C++约定,使用0来表示“不存在”,而不是冒着延迟风险并引起关于pure的争论。 =0语法符合我的观点,即函数体是函数的初始化器,也符合虚拟函数集通常视为函数指针向量的(简单但通常足够的)观点。 [...]

1§13.2.3 语法


33

《C++标准》第9.2节给出了类成员的语法。其中包括这个产生式:

pure-specifier:
    = 0

值本身并没有什么特别之处。"= 0" 只是表示 "这个函数是纯虚函数" 的语法。它与初始化、空指针或数字值零无关,尽管与这些东西的相似之处可能有助于记忆。


6
+1 针对 C++ 标准的参考。令人惊讶的是,最佳答案只得到了 1 票。阅读标准应该是解决 C++ 问题的第一步。 - mloskot
8
也许是因为它没有回答 OP 的问题,只是重申了情况? - just somebody
7
@just somebody - 这里包含了标准引用,说明了纯虚函数声明的语法以及该语法使用纯净限定符= 0。你还想知道什么吗?这与问为什么函数体要用{}括起来是一样的。答案是,因为这是C++语法定义的方式。 - mloskot

17

我不确定这是否有任何意义。 这只是语言的句法。


17

C++一直回避引入新的关键字,因为新的保留字会破坏使用这些单词作为标识符的旧程序。它经常被视为语言的一个优点,尽可能地尊重旧代码。

= 0语法确实可能被选择,因为它类似于将vtable条目设置为0,但这纯粹是象征性的。(大多数编译器将此类vtable条目分配给一个发出错误并终止程序的存根。)这种语法主要是因为它以前没有被用过,而且它避免了引入新的关键字。


5
感谢解释引入新关键字的缺点,这有助于理解其背后的原理。但是我觉得C++语法过于复杂了,希望他们能够使它更加人性化易读。在我看来,添加一个 pure 关键字会非常好。无论如何,理解其背后的原理是很好的事情。 - Keith Pinson
如果你想要一个纯关键字,你可以使用 #define pure = 0 - jdh8
@ThePhD:我记得他在《D&E》的某个地方也这样说过。(不过我太懒了,没去查。) - sbi
@sbi Jerry Coffin的回答引用了这个。 - milleniumbug
@milleniumbug:哦。:-) - sbi
显示剩余2条评论

11

C++必须有一种方法来区分纯虚函数和普通虚函数的声明。他们选择使用“= 0”语法。他们也可以通过添加pure关键字来实现相同的功能,但是C++并不喜欢添加新的关键字,更喜欢使用其他机制来引入特性。


2
-0:当你自己没有实质性的话可说时,可以使用一个广泛的引用(请参见Jerry Coffin的答案+1 ;) - just somebody

7

在这种情况下,没有任何东西被“初始化”或“赋值”为零。 = 0 只是由 =0 标记组成的语法结构,与初始化或赋值完全无关。

它与“vtable”中的任何实际值都没有关系。C++语言没有“vtable”或类似的概念。各种“vtable”只不过是特定实现的细节而已。


3
我记得读过一个解释,有趣的语法是因为用这种方式比引入另一个关键词来实现同样的功能更容易(从标准接受的角度而言)。我相信这在Bjarne Stroustrup的《C++设计与演化》一书中有提到。

2

我认为这只是C++语法的一部分。我不认为编译器在特定的二进制格式中实现这个有任何限制。对于早期的C++编译器,你的想法可能是正确的。


2

= 0声明了一个纯虚函数

我理解的是,这是为了将此函数的vtable条目初始化为NULL,而在此处使用任何其他值会导致编译时错误。

我认为这不是真的。这只是一种特殊的语法。vtable是实现定义的。没有人说必须在构造时实际将纯成员的vtable条目清零(尽管大多数编译器处理vtable类似)。


4
实际上这并不是真的。为纯虚函数提供一个定义并没有错。= 0 的唯一作用是使整个类变为抽象类并禁止对纯函数进行虚拟调用。非虚拟调用仍然完全没问题,当你提供了定义时就会使用它。 - AnT stands with Russia
只需查看godbolt输出。没有歧义或猜测的余地。稍后我自己会看一下。 - Lewis Kelsey
看起来它用 __cxa_pure_virtual https://arobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/abstract_classes.html 替换了 Base::f() 的条目。 - Lewis Kelsey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接