为什么纯虚函数由0初始化?


147

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

virtual void fun () = 0 ;

即,始终将其分配为0。

我了解的是,这是将此函数的vtable条目初始化为NULL,此处的任何其他值都会导致编译时错误。这种理解正确与否?


12
请注意,vtable不是语言要求,而只是虚拟方法的实现选项。编译器可以创建不同的实现相同的抽象(即无虚函数表,没有任何元素还有为0)
dribeas大卫-罗德里格斯

@hype关于您的补充问题-这就是我(和其他几个人)的回答。

只是好奇,如果我给我,会发生什么事 virtual void func() = 100;
krithikaGopalakrisnan '19

Answers:


161

原因=0是Bjarne Stroustrup认为在实现该功能时,他不能在C ++社区之外获得另一个关键字,例如“ pure”。这在他的书《 C ++的设计和演变》第13.2.3节中进行了描述:

之所以选择= 0好奇的语法是因为……当时我还没有机会接受新的关键字。

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


4
是的,这只是语法。我看过许多#define PURE = 0的项目,他们会说virtual void Foo()PURE;
i_am_jorf

79
请上帝让我远离那些项目:-)

27
它比#define BEGIN {#define END} ;-)差很多,而我有时看到了。
Toon Krijthe,2010年

5
这种漂亮的东西使我认为C ++不够完善。考虑到它的用途很奇怪,这很奇怪。我希望随着时间的流逝,语言会变得更好。
11

19
因此,换句话说,Bjarne被“面对最后期限”并“被黑客利用”以克服“设计缺陷”;)(只是刻薄)
Carl

78

与大多数有关C ++设计的“为什么”问题一样,首先要看的是Bjarne Stroustrup 1撰写的《 C ++的设计和演进》

=0选择好奇的语法而不是引入新关键字的明显替代方法,pure或者 abstract因为当时我看不到接受新关键字的机会。如果我建议的话pure,2.0版将没有抽象类。在更好的语法和抽象类之间做出选择之后,我选择了抽象类。我没有冒延迟和招致某些争执的风险 pure,而是使用了传统的C和C ++约定,即使用0表示“不在那儿”。该=0语法与配合我认为一个功能体为功能也与所述一组虚拟功能的(简单,但通常是足够的)视图被实现为函数指针的向量初始化。[...]

1 §13.2.3语法


29

C ++标准的9.2节提供了类成员的语法。它包括此生产:

pure-specifier:
    = 0

价值没有什么特别的。“ = 0”只是表示“此函数是纯虚函数”的语法。它与初始化,空指针或数字零无关,尽管与这些东西的相似之处可能具有助记符。


5
+1代表C ++标准。迄今为止,最佳答案只有一个,这真是令人惊讶。阅读标准应该是解决C ++问题的第一步。
mloskot 2010年

7
@mloskot:也许是因为它没有回答OP的问题,只是重述了情况?
某人2010年

6
@just somebody-它包括标准引文,该标准陈述了纯虚函数声明的语法是什么,并且该语法使用了pure-specifier = 0您还想知道什么?这将与询问为什么用{}包裹函数体是相同的,答案是,因为这是C ++语法定义的。
mloskot 2010年

19

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


16

C ++总是回避引入新的关键字,因为新的保留字破坏了使用这些字作为标识符的旧程序。通常,它尽可能地尊重旧代码是该语言的优势之一。

= 0可能确实已选择语法,因为它酷似设置虚函数表条目0,但是这纯粹是象征性的。(大多数编译器将此类vtable条目分配给存根,该存根在中止程序之前会产生错误。)之所以选择该语法,是因为该语法之前没有被使用过,并且节省了引入新关键字的可能性。


3
+1用于说明引入新关键字的弊端。这对理解基本原理很有帮助,但是C ++语法对我来说似乎是令人费解的,我希望他们能使它更易于理解- pure在我的书中,使用关键字非常有用。无论如何,了解原理是一件好事。
基思·品森

@KeithPinson如果您想要一个纯关键字,则可以#define pure = 0
jdh8

@ jdh8:gh。只是...呃
2016年

附带说明一下,在与Bjarne一起上的一堂课中,他说他真的很想将“纯”关键字添加到C ++中……但是他试图在将C ++编译器交付之前的很晚的一个周期中获取它。不到两个星期)。表面上看,它没有加入
。– ThePhD

@ThePhD:ISTR他也在D&E的某处说了这一点。(不过,我太懒了,无法查找它。)
sbi

11

C ++必须有一种方法可以将纯虚函数与普通虚函数的声明区分开。他们选择使用= 0语法。通过添加一个纯关键字,他们可以轻松地做到这一点。但是C ++非常讨厌添加新关键字,并且更喜欢使用其他机制来引入功能。


2
-0:当您自己无话可说时,请使用广泛的引号(请参阅杰里·科芬的+1回答;)
某人

7

在这种情况下,没有“初始化”或“分配”为零。= 0只是由=和组成的语法结构0,它与初始化或赋值完全没有关系。

它与“ vtable”中的任何实际值无关。C ++语言没有“ vtable”或类似的概念。各种“ vtables”无非就是具体实现的细节。


3

我记得读过,有趣的语法的理由是(就标准接受而言)比引入另一个可以做同样事情的关键字更容易。

我相信Bjarne Stroustrup在《 C ++的设计和演变》中提到了这一点。


2

我认为这只是C ++语法的一部分。我认为对于给定的特定二进制格式,编译器如何实际实现此功能没有任何限制。您以为可能是早期C ++编译器的正确选择。


2

= 0声明了一个纯虚函数

可以理解的是,这是将此函数的vtable条目初始化为NULL,此处的任何其他值都会导致编译时错误

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


4
这实际上是不正确的。提供纯虚函数的定义没有错。唯一要做的= 0是使整个类抽象化并禁止对纯函数的虚拟调用。使用定义(如果已提供)时,非虚拟调用仍然可以正常执行。
AnT 2010年

只需查看Godbolt输出即可。没有歧义或猜测的余地。我会看看自己以后
刘易斯凯尔西

看来它用__cxa_pure_virtual arobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/…代替了Base :: f()
Lewis Kelsey,

1

好吧,您也可以初始化vtable条目以指向实际功能”

 virtual void fun()
 {
     //dostuff()
 }

看起来很直观,可以将vtable条目定义为不指向任何地方(0)或指向函数。让您为其指定自己的值可能会导致它指向垃圾而不是函数。但这就是为什么允许“ = 0”而不允许“ = 1”的原因。我怀疑尼尔·巴特沃思(Neil Butterworth)为何使用“ = 0”是正确的


1
即使我也有类似的看法,但是由于许多人都引用了标准和Bjarne的评论,因此我们极少有争执的可能性:)
mukeshkumar 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.