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

sha*_*oth 50 c++ inheritance sizeof language-lawyer

假设我有一个带有一些成员变量且没有虚函数的基类:

class Base {
   int member;
};
Run Code Online (Sandbox Code Playgroud)

以及从非虚拟方式派生Base并且没有新成员变量的派生类,再次没有虚函数:

class Derived : Base {
};
Run Code Online (Sandbox Code Playgroud)

显然sizeof(Derived)不能小于sizeof(Base).

sizeof(Derived)要求等于sizeof(Base)

Tri*_*dle 18

从5.3.2 [expr.sizeof]

应用于类时,结果[of sizeof]是该类对象中的字节数,包括在数组中放置该类型对象所需的任何填充.最派生类的大小应大于零(1.8).

从1.8 [intro.object]

除非它是位字段(9.6),否则最派生的对象应具有非零大小并且应占用一个或多个存储字节.基类子对象可以具有零大小.POD类型(3.9)的对象应占用连续的存储字节.

并注意:

由于虚基类和对基类子对象的不太严格的填充要求,基类子对象的实际大小可能小于将sizeof应用于子对象的结果.

将这些放在一起,我认为它告诉你的是,sizeof除了结果大于零之外,你无法保证可能会告诉你什么.事实上,它似乎甚至没有保证sizeof(Derived) >= sizeof(Base)!


Ker*_* SB 13

没有这样的要求.

我能想到的语言中唯一相关的部分是,每个对象,无论是否完整,以及是否是大多数派生的,都有一个身份,由一对地址和类型给出.参看 C++ 11 1.8/6:

如果一个是另一个的子对象,或者如果至少一个是零大小的基类子对象并且它们是不同类型的,则不是位字段的两个对象可以具有相同的地址; 否则,他们应有不同的地址.

因此,示例中派生最多的对象和基础子对象必须具有不同的标识.

对于编译器来说,同时给出两者BaseDerived大小都是有意义的1,但这不是强制性的.如果Base尺寸为1729并且Derived尺寸为2875,那将是可以接受的.

  • @KerrekSB引入"优化"是为了允许空类在它们是基础时不占用空间,并且被称为空基类优化,但实际采用的措辞实际上允许任何基类占用不同的字节数. `sizeof`报道.如果你有`struct Base {int i;这实际上是有意义的.char c; }; struct Derived:Base {char c; };`; 对齐注意事项可能意味着`sizeof(Base)== 8`,但`sizeof(Derived)== 8`,尽管`Derived`添加了一个数据成员. (5认同)
  • 呵呵,我想知道标准是否对非原始类型施加了任何限制(当涉及到它们的大小时).也许它可以让'基地'2875和'衍生'1729只是为了笑=) (2认同)

Dav*_*vid 9

有趣的问题.我有一个例子,其中用一个额外的字段派生类是大小相同的作为基类. (这应该是一个评论,但是太大了;请接受其他答案之一,尽管如果它很有趣,欢迎赞成.)

考虑一下这个简单的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;
}
Run Code Online (Sandbox Code Playgroud)

你期望输出sizeof(int)是什么,如果是4?也许是这样的:

A: 0
B: 4
int: 4
Run Code Online (Sandbox Code Playgroud)

我的编译器 - Embarcadero C++ Builder 2010 - 给出了输出:

A: 8
B: 8
int: 4
Run Code Online (Sandbox Code Playgroud)

换句话说,在派生类中添加额外字段不会使派生类更大.

有一些关于兼容性选项零长度空基类的帮助文件主题的原因.

通常,类的大小至少为一个字节,即使该类没有定义任何数据成员.设置此选项时,编译器会忽略内存布局的未使用字节以及任何派生类的总大小; 空基类不会占用派生类中的空间.默认= False

对于此编译器,具有默认编译器设置的类的大小似乎是8个字节,而不是一个,实际上更改此代码示例的此设置无效.

您可能还会发现有关基类大小和上述优化的文章很有趣.它讨论了为什么类必须具有至少一个字节的大小,优化的作用,以及深入研究成员函数的表示等:

实际上,该标准要求物体的尺寸永远不应为零; 它还要求在派生对象中,基类的成员应出现在派生类的用户声明数据成员之前.但是,基类子对象不被视为完整对象.因此,可以在不违反规则的情况下从派生对象中删除基类子对象.换句话说,在对象t中,S和x的偏移可能重叠......

请阅读文章,了解该报价的完整背景.