简体   繁体   English

如果与基类相比没有新的成员变量,C++ 是否允许增加派生类的大小?

[英]Is C++ allowed to increase the derived class size if there're no new member variables compared to the base class?

Suppose I have a base class with some member variables and no virtual functions:假设我有一个带有一些成员变量而没有虚函数的基类:

class Base {
   int member;
};

and a derived class that derives in a non-virtual way from Base and has no new member variables an again no virtual functions:以及以非虚拟方式从Base派生的派生类,并且没有新的成员变量,也没有虚拟函数:

class Derived : Base {
};

Obviously sizeof(Derived) can't be smaller than sizeof(Base) .显然sizeof(Derived)不能小于sizeof(Base)

Is sizeof(Derived) required to be equal to sizeof(Base) ? sizeof(Derived)需要等于sizeof(Base)

From 5.3.2 [expr.sizeof]从 5.3.2 [expr.sizeof]

When applied to a class, the result [of sizeof ] is the number of bytes in an object of that class including any padding required for placing objects of that type in an array.当应用于类时,结果 [of sizeof ] 是该类的对象中的字节数,包括将该类型的对象放置在数组中所需的任何填充。 The size of a most derived class shall be greater than zero (1.8).最派生类的大小应大于零 (1.8)。

From 1.8 [intro.object]从 1.8 [intro.object]

Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage.除非它是位域 (9.6),否则最衍生的对象应具有非零大小并应占用一个或多个字节的存储空间。 Base class sub-objects may have zero size.基类子对象的大小可能为零。 An object of POD type (3.9) shall occupy contiguous bytes of storage. POD 类型 (3.9) 的对象应占用连续的存储字节。

and a note:和一个注释:

The actual size of a base class subobject may be less than the result of applying sizeof to the subobject, due to virtual base classes and less strict padding requirements on base class subobjects.由于虚拟基类和对基类子对象的不太严格的填充要求,基类子对象的实际大小可能小于将 sizeof 应用于子对象的结果。

Put these together and I think what it's telling you is that you have no guarantees whatsoever as to what sizeof might tell you, other than the result will be greater than zero.把这些放在一起,我认为它告诉你的是,你不能保证sizeof可能告诉你什么,除了结果将大于零。 In fact, it doesn't even seem to guarantee that sizeof(Derived) >= sizeof(Base) !事实上,它似乎甚至不能保证sizeof(Derived) >= sizeof(Base)

There is no such requirement.没有这样的要求。

The only relevant part of the language I can think of is that every object, whether complete or not, and whether most-derived or not, has an identity , which is given by the pair of its address and its type.我能想到的语言中唯一相关的部分是每个对象,无论是否完整,无论是否是大多数派生的,都有一个identity ,它由其地址和类型对给出。 Cf.参见C++11 1.8/6: C++11 1.8/6:

Two objects that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types;如果一个对象是另一个对象的子对象,或者至少一个是零大小的基类子对象并且它们属于不同类型,则两个不是位域的对象可能具有相同的地址; otherwise, they shall have distinct addresses.否则,它们应具有不同的地址。

So both the most-derived object and the base subobject of your example must have distinct identities.因此,您示例中派生最多的对象和基础子对象都必须具有不同的身份。

It would certainly make sense for a compiler to give both Base and Derived a size of 1 , but this is not mandatory.编译器将BaseDerived的大小都指定为1肯定是有意义的,但这不是强制性的。 It would be acceptable if the Base had size 1729 and Derived had size 2875.如果Base大小为 1729 而Derived大小为 2875 则是可以接受的。

Interesting question.有趣的问题。 I have an example where a derived class with an extra field is the same size as an empty base class.我有一个示例,其中带有额外字段的派生类与基类的大小相同 (This should be a comment but is much too large; please accept one of the other answers, although upvotes are welcome if it's interesting.) (这应该是评论,但太大了;请接受其他答案之一,尽管如果有趣,欢迎投票。)

Consider this trivial C++ program:考虑这个简单的 C++ 程序:

class A {};

class B : public A {
    int m_iInteger;
};

int _tmain(int argc, _TCHAR* argv[])
{
    printf("A: %d\r\n", sizeof(A));
    printf("B: %d\r\n", sizeof(B));
    printf("int: %d\r\n", sizeof(int));

    return 0;
}

What would you expect the output to be, if sizeof(int) is 4?如果sizeof(int)为 4,您希望输出是什么? Perhaps something like:也许是这样的:

A: 0
B: 4
int: 4

? ?

My compiler - Embarcadero C++ Builder 2010 - gives the output:我的编译器 - Embarcadero C++ Builder 2010 - 给出输出:

A: 8
B: 8
int: 4

In other words, adding an extra field in the derived class does not make the derived class bigger.换句话说,在派生类中添加额外的字段不会使派生类变大。

There is some insight into why with the help file topic on the compatibility option Zero-length empty base class .关于兼容性选项 Zero-length empty base class的帮助文件主题, 可以深入了解原因。

Usually the size of a class is at least one byte, even if the class does not define any data members.通常一个类的大小至少是一个字节,即使该类没有定义任何数据成员。 When you set this option, the compiler ignores this unused byte for the memory layout and the total size of any derived classes;当您设置此选项时,编译器将忽略此未使用的字节用于内存布局和任何派生类的总大小; empty base classes do not consume space in derived classes.空基类不占用派生类中的空间。 Default = False默认值 = 假

It appears that the size of a class with default compiler settings for this compiler is 8 bytes, not one, and in fact changing this setting for this code example has no effect.看起来这个编译器的默认编译器设置的类的大小是 8 个字节,而不是一个,实际上更改此代码示例的此设置没有任何效果。

You may also find this article on base class sizes and the above optimization interesting.您可能还会发现这篇关于基类大小和上述优化的文章很有趣。 It discusses why classes must have a size of at least one byte, what the optimization does, and delves into representation of member functions etc too:它讨论了为什么类必须具有至少一个字节的大小,优化的作用,并深入研究成员函数的表示等:

Indeed, the standard requires that the size of an object shall never be zero;事实上,该标准要求对象的大小永远不能为零; it also requires that in a derived object data members of the base class(es) shall appear before user-declared data members of the derived class.它还要求在派生对象中基类的数据成员应出现在派生类的用户声明的数据成员之前。 However, a base class subobject isn't considered a complete object.但是,基类子对象不被视为完整对象。 Therefore, it's possible to remove the base class subobject from the derived object without violating the rules.因此,可以在不违反规则的情况下从派生对象中删除基类子对象。 In other words, in the object t, the offset of S and x may overlap...换句话说,在对象 t 中,S 和 x 的偏移量可能会重叠......

Please read the article for the full context of that quote.请阅读文章以了解该报价的完整上下文。

class Base {
 // int member;            I have just created an empty base class.
};

class Derived : Base {
};

Now gcc compiler would give "size>0" for the both the objects created by Base and Derived classes.现在 gcc 编译器将为 Base 和 Derived 类创建的对象提供“size>0”。 gcc compiler just provides the presence of address for the objects to the user. gcc 编译器只是向用户提供对象的地址。

  Note:Derived class would contain base class members, so obviously we can think of 
  sizeof(derived class) greater then sizeof(base class). But this depends on the compiler 
  if it allocates some extra space while defining the derived class. 

My present gcc compiler showed the sizeof objects of both Base and Derived to be same.我目前的 gcc 编译器显示 Base 和 Derived 的对象大小相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM