为啥纯虚函数初始化为0?

Posted

技术标签:

【中文标题】为啥纯虚函数初始化为0?【英文标题】:Why is a pure virtual function initialized by 0?为什么纯虚函数初始化为0? 【发布时间】:2011-01-10 12:40:41 【问题描述】:

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

virtual void fun () = 0 ;

即,它总是分配给 0。

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

【问题讨论】:

请注意,vtable 不是语言要求,而只是虚方法的实现选项。编译器可以创建具有不同实现的相同抽象(即,没有 vtable,并且没有任何元素有 0) @hype 回复您的补充问题 - 这就是我的回答(和其他几个人)所说的。 只是好奇,如果我给会发生什么,virtual void func() = 100; 【参考方案1】:

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

选择了奇怪的 =0 语法... 因为当时我看不到机会 接受一个新的关键字。

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

【讨论】:

是的,这只是语法。我见过很多#define PURE =0 的项目,他们会说 virtual void Foo() PURE; 请上帝让我远离那些项目 :-) 它比 #define BEGIN #define END 差很多;-) 我有时也看到过。 这种漂亮的东西让我觉得C++不是很精致。考虑到它被如此频繁地使用,这很奇怪。我希望随着时间的流逝,语言会更好。 所以,换句话说,Bjarne 是“面临最后期限”并“使用黑客”来克服“设计缺陷”;)(只是开玩笑)【参考方案2】:

与大多数关于 C++ 设计的“为什么”问题一样,首先要看的是 C++ 的设计和演变,作者是 Bjarne Stroustrup1

选择了奇怪的=0 语法 在明显的选择 引入新关键字pureabstract 因为当时我看到 没有机会获得新的关键字 公认。如果我建议pure, 版本 2.0 将在没有 抽象类。给定一个选择 在更好的语法和抽象之间 类,我选择了抽象类。 而不是冒着延误和 招致某些争吵 pure,我用的是传统的C和C++ 使用 0 表示的约定 “不在那里。” =0 语法符合 我认为函数体是 函数的初始化器也与 (简单,但通常足够) 虚函数集的视图 被实现为一个向量 函数指针。 [...]

1§13.2.3 语法

【讨论】:

【参考方案3】:

C++ 标准的第 9.2 节给出了类成员的语法。它包括这个产品:

pure-specifier:
    = 0

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

【讨论】:

+1 用于引用 C++ 标准。令人惊讶的是,这是最好的答案之一,到目前为止只获得了 1 票。阅读标准应该是解决 C++ 问题的第一步。 @mloskot:也许是因为它没有回答 OP 的问题,只是重申了情况? @just someone - 它包括标准引用,说明纯虚函数声明的语法是什么,语法使用纯说明符= 0您还想知道什么?这就像问为什么函数体用 包裹一样,答案是,因为这是 C++ 语法定义的。【参考方案4】:

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

【讨论】:

【参考方案5】:

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

= 0 语法可能确实已被选择,因为它类似于将 vtable 条目设置为 0,但这纯粹是象征性的。 (大多数编译器将此类 vtable 条目分配给在中止程序之前发出错误的存根。)选择语法主要是因为它以前没有用于任何东西,并且它节省了引入新关键字。

【讨论】:

+1 用于解释引入新关键字的缺点。这有助于理解其基本原理,但 C++ 语法对我来说似乎是荒谬的,我希望他们能让它更易于阅读——pure 关键字在我的书中会很棒。无论如何,理解其中的原理是件好事。 @KeithPinson 想要纯关键字可以#define pure = 0 @jdh8:呃。只是……呃。 作为旁注,在与 Bjarne 一起上课时,他说他真的很想将“纯”关键字引入 C++ ......但他试图在 C++ 之前的周期很晚的时候得到它编译器即将发货(IIRC 不到两周)。从表面上看,它没有成功。 @ThePhD:ISTR 他也在 D&E 的某个地方这么说。 (不过我懒得查了。)【参考方案6】:

C++ 必须有一种方法来区分纯虚函数和普通虚函数的声明。他们选择使用= 0 语法。他们可以通过添加一个纯关键字轻松地做到这一点。但是 C++ 非常不愿意添加新的关键字,而是更喜欢使用其他机制来引入特性。

【讨论】:

-0:当您自己没有什么实质性的要说时,请使用广泛的引用(请参阅 Jerry Coffin 对 +1 的回答;)【参考方案7】:

在这种情况下,没有“初始化”或“分配”零。 = 0 只是一个由 =0 标记组成的句法结构,它与初始化或赋值绝对无关。

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

【讨论】:

【参考方案8】:

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

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

【讨论】:

【参考方案9】:

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

【讨论】:

【参考方案10】:

= 0声明了一个纯虚函数

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

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

【讨论】:

这实际上不是真的。为纯虚函数提供定义并没有错。 = 0 所做的唯一一件事就是使整个类抽象化并禁止对纯函数的 virtual 调用。非虚拟调用仍然完全可以,这是使用定义(如果您提供了)的时候。 看一下godbolt的输出。没有模棱两可或猜测的余地。以后我自己去看看 它似乎用__cxa_pure_virtualarobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/…而不是Base::f()替换了条目【参考方案11】:

嗯,你也可以初始化 vtable 条目以指向一个实际的函数”

 virtual void fun()
 
     //dostuff()
 

看起来很直观,可以将 vtable 条目定义为无处 (0) 或函数。让您为它指定自己的值可能会导致它指向垃圾而不是函数。但这就是为什么允许“= 0”而不允许“= 1”的原因。我怀疑 Neil Butterworth 关于为什么使用“= 0”是正确的

【讨论】:

即使我也有类似的意见,但由于许多人引用了相同的标准和 Bjarne 的 cmets,我们争论的机会很小:)

以上是关于为啥纯虚函数初始化为0?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要 C++ 中的纯虚析构函数?

为啥纯虚析构函数需要实现

运算符重载如何声明为纯虚函数?

纯虚函数,抽象类

纯虚函数

C++ 纯虚函数