我们总是将纯虚函数声明为:
virtual void fun () = 0 ;
即,它始终分配为 0。
我的理解是,这是将此函数的 vtable 条目初始化为 NULL,此处的任何其他值都会导致编译时错误。这种理解正确与否?
我们总是将纯虚函数声明为:
virtual void fun () = 0 ;
即,它始终分配为 0。
我的理解是,这是将此函数的 vtable 条目初始化为 NULL,此处的任何其他值都会导致编译时错误。这种理解正确与否?
使用的原因=0
是 Bjarne Stroustrup 认为他无法获得另一个关键字,例如在实现该功能时超越 C++ 社区的“纯”。这在他的书《C++ 的设计与演变》第 13.2.3 节中有所描述:
选择了奇怪的 =0 语法……因为当时我看不到接受新关键字的机会。
他还明确指出,这不需要将 vtable 条目设置为 NULL,并且这样做不是实现纯虚函数的最佳方式。
与大多数关于 C++ 设计的“为什么”问题一样,首先要看的是Bjarne Stroustrup的 The Design and Evolution of C++ 1:
选择了奇怪的
=0
语法而不是引入新关键字的明显替代方案,pure
或者abstract
因为当时我认为没有机会接受新关键字。如果我建议pure
,2.0 版将在没有抽象类的情况下发布。考虑到更好的语法和抽象类之间的选择,我选择了抽象类。我没有冒延迟和引发某些争吵的风险pure
,而是使用了传统的 C 和 C++ 约定,使用 0 表示“不存在”。该=0
语法符合我的观点,即函数体是函数的初始化器,也符合(简单但通常足够)作为函数指针向量实现的虚函数集的视图。[ ... ]
1 §13.2.3 语法
C++ 标准的第 9.2 节给出了类成员的语法。它包括这个生产:
pure-specifier:
= 0
价值没有什么特别之处。“= 0”只是表示“这个函数是纯虚拟的”的语法。它与初始化或空指针或数值零无关,尽管与这些事物的相似性可能具有助记符的价值。
我不确定这背后是否有任何意义。这只是语言的语法。
C++ 一直避免引入新的关键字,因为新的保留字会破坏使用这些字作为标识符的旧程序。尽可能尊重旧代码通常被视为该语言的优势之一。
= 0
可能确实选择了语法,因为它类似于将 vtable 条目设置为,0
但这纯粹是象征性的。(大多数编译器将此类 vtable 条目分配给在中止程序之前发出错误的存根。)选择语法主要是因为它以前没有用于任何东西,并且它节省了引入新关键字。
C++ 必须有一种方法来区分纯虚函数和普通虚函数的声明。他们选择使用= 0
语法。他们可以通过添加一个纯关键字轻松地做到这一点。但是 C++ 非常不愿意添加新的关键字,并且更喜欢使用其他机制来引入特性。
在这种情况下,没有什么是“初始化”或“分配”为零的。= 0
只是一个由=
和0
标记组成的句法结构,它与初始化或赋值绝对没有关系。
它与“vtable”中的任何实际值无关。C++ 语言没有“vtable”或类似的概念。各种“vtables”只不过是具体实现的细节。
我记得读过有趣的语法的理由是它比引入另一个可以做同样事情的关键字更容易(在标准接受方面)。
我相信 Bjarne Stroustrup 在 The Design and Evolution of C++ 中提到了这一点。
我会假设这只是 C++ 语法的一部分。我认为编译器如何为给定的特定二进制格式实际实现这一点没有任何限制。您的假设可能对早期的 C++ 编译器是正确的。
= 0
声明一个纯虚函数。
可以理解的是,这是将此函数的 vtable 条目初始化为 NULL,此处的任何其他值都会导致编译时错误
我不认为那是真的。这只是特殊的语法。vtable 是实现定义的。没有人说纯成员的 vtable 条目必须在构造时实际归零(尽管大多数编译器处理 vtable 类似)。
好吧,您还可以初始化 vtable 条目以指向实际函数”
virtual void fun()
{
//dostuff()
}
看起来很直观,可以将 vtable 条目定义为无处指向 (0) 或函数。让您为它指定自己的值可能会导致它指向垃圾而不是函数。但这就是为什么允许“= 0”而不允许“= 1”的原因。我怀疑 Neil Butterworth 关于为什么使用“= 0”是正确的