3

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 分配了内存,但没有为结构实例分配内存。所以我只是想确定规范是否排除了这种编译器行为。

谢谢!

4

4 回答 4

7

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

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

然而,过去的 C++ 编译器确实经常偏离标准并且彼此之间存在相当大的偏差,因此您的同事可能也是对的。

于 2011-04-27T02:33:52.573 回答
3

我无法通过快速搜索找到它的在线参考,但我很确定编译器可以对任何类的布局做任何事情;class特别是,在没有任何虚方法的类中,是否允许放置structvftp ,取决于当天的感受,是否声明为月亮,或者别的什么。我知道的唯一限制是派生对象的顶部应匹配其第一个(非虚拟)基类的布局。而且我什至不确定它是否必须是第一个。

您在任何时候都不应该依赖特定编译器对对象布局的决定。许多编译器无一例外地在所有对象中放置一个 vftp,以便为调试器提供运行时类型信息,或者只是为了让他们自己的生活更轻松。有些没有。您没有合理的方式知道,除非通过sizeof运营商。

于 2011-04-27T02:30:07.707 回答
2

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

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

于 2011-04-27T02:29:25.407 回答
-1

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

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

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

于 2011-04-27T02:19:11.167 回答