c++规范是否允许非虚类的实例包含虚值表指针的内存?

Does the C++ spec allow an instance of a non-virtual class to include memory for a vtable pointer?

本文关键字:包含虚 实例 内存 指针 许非虚 范是否 是否 c++      更新时间:2023-10-16

c++规范允许非虚类的实例包含虚表指针的内存吗?我之所以问这个问题,是因为一位同事说他曾经使用过一个c++编译器,其中发生了以下情况:

  class MyClass
  {
     public:
     HeaderStruct header; //This had extra words
     BodyStruct     message_body;
  };

然后他把代码改成了这样,去掉了多余的单词:

  struct MyClass
  {
     HeaderStruct header; //This did not have extra words
     BodyStruct     message_body;
  };

这些类型都不是虚的或派生自虚的。所以理论是,也许这个特定的编译器为类实例分配内存,而不是为结构实例分配内存。所以我只是想确定这样的编译器行为是否被规范排除。

谢谢!

根据标准,'struct'和'class'是同义词,只影响对类定义中的基和成员的默认访问。

标准定义POD(普通旧数据)。POD不能有用户定义的构造函数、析构函数、赋值操作符、非静态引用成员和任何虚函数(它的非静态成员也不应该有这些东西)。pod有严格的内存布局规则(为了与C兼容),因此实现不能添加任何变量或RTTI信息或类似的东西。

然而,过去的c++编译器确实经常偏离标准,而且彼此之间也相差很大,所以你的同事可能也是对的。

我无法通过快速搜索找到在线参考,但我很确定编译器被允许对任何类的布局做任何事情;特别是,在没有任何虚拟方法的类中,允许放置vftp或不放置vftp,这取决于它当天的感觉,是否声明为classstruct(在c++中是等效的,除了默认的访问说明符),月相或其他任何东西。我所知道的唯一限制是派生对象的顶部必须匹配其第一个(非虚拟)基类的布局。我甚至不确定它一定是第一个。

在任何时候都不应该依赖于特定编译器对对象布局的决定。许多编译器将vftp毫无例外地放在所有对象中,以便向调试器提供运行时类型信息,或者只是为了使它们自己的工作更轻松。一些不喜欢。你没有合理的方法知道,除非通过sizeof操作符。

没有"虚拟类"这回事。您可能指的是虚拟继承,它涉及在类名之前使用virtual关键字,但是虚拟性适用于继承关系,而不是类本身。或者你只是指包含虚函数的类。

无论如何,c++规范根本没有提到虚表;这些是特定于实现的。通常,只有当类包含虚函数、具有虚基或继承了具有虚基的其他类时,才会添加虚表。但是,在every类的every实例中放置一个虚表是完全有效的实现。

类的虚修饰符仅在可能不止一次继承该类时使用。在I/O流库中,istream和ostream都继承自ios_base,而iostream继承自istream和ostream。虚修饰符允许您继承两次,而无需获得基类成员的两个副本。

但是任何方法都可以是虚的,即使在非虚类中也是如此——因此任何类都可以有虚函数表。

但是你的问题的真正答案:)是类和结构几乎是相同的,除了在类中,成员默认是私有的,而在结构中,他们默认是公共的。