C ++规范是否允许非虚拟类的实例包含vtable指针的内存?

时间:2011-04-27 02:07:36

标签: c++ vtable

C ++规范是否允许非虚拟类的实例包含vtable指针的内存?我问这个,因为一位同事说他曾经使用过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;
  };

这些类型都不是虚拟的,也不是虚拟的。所以理论上可能这个特定的编译器为类实例分配了vptr的内存,但是没有为struct实例分配内存。所以我只是想确定规范是否排除了这种编译器行为。

谢谢!

4 个答案:

答案 0 :(得分:7)

通过标准“struct”和“class”是同义词,它们仅影响对类定义中的基础和成员的默认访问。

标准定义POD(普通旧数据)。 POD可能没有用户定义的构造函数,析构函数,赋值运算符,非静态引用成员和虚拟的任何东西(它的非静态成员也不应该有这样的东西)。 POD具有严格的内存布局规则(为了与C兼容),因此实现不能添加任何vtable或RTTI信息等。

然而,旧时代的C ++编译器经常偏离标准而且相互之间的偏差很大,所以你的同事也可能是对的。

答案 1 :(得分:3)

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

您不应该在任何时候依赖于特定编译器对对象布局的决定。许多编译器毫无例外地将vftp放在所有对象中,以便为调试器提供运行时类型信息,或者只是为了让自己的生活更轻松。有些人没有。除了通过sizeof运算符之外,您没有合理的了解方式。

答案 2 :(得分:2)

没有“虚拟课”这样的东西。您可能需要virtual inheritance,这涉及在类名之前使用virtual关键字,但虚拟适用于继承关系,而不是类本身。或许你只是指一个包含虚函数的类。

无论如何,C ++规范根本没有提到虚拟表的任何内容;那些是特定的实现。通常,只有当类包含虚函数,具有虚拟基础或从其他类继承时,才会添加虚拟表。但是,将虚拟表放在每个 类的每个实例中都是完全有效的。

答案 3 :(得分:-1)

只有在/您可能多次从类继承时才使用类的虚拟修饰符。在I / O流库中,istream和ostream都从ios_base继承,iostream继承了istream和ostream。虚拟修饰符允许您继承两次而不获取基类成员的两个副本。

但是任何方法都可以是虚拟的,即使在非虚拟类中也是如此 - 因此任何类都可以有一个vtable。

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