单独继承的派生类的大小

Posted

技术标签:

【中文标题】单独继承的派生类的大小【英文标题】:Size of singly inherited derived classes 【发布时间】:2016-07-11 10:01:04 【问题描述】:

以下代码 (online version) 基于 Stanley Lippman 所著的“C++ 对象模型内部”一书的第 3.4 节(参见硬拷贝的第 85-86 页或PDF version 的第 64 页)。

#include <iostream>
#include <cstddef> // defines offset

struct Base

    int  w;
    char x;
;

struct Derived1 : Base

    char y;
;

struct Derived2 : Derived1

    char z;
;

int main()

    std::cout << "sizeof(Base) = " << sizeof( Base ) << "\n";
    std::cout << "sizeof(Derived1) = " << sizeof( Derived1 ) << "\n";
    std::cout << "sizeof(Derived2) = " << sizeof( Derived2 ) << "\n";

    std::cout << "Offset of x in Derived2 = " << offsetof( Derived2 , x) << "\n";
    std::cout << "Offset of y in Derived2 = " << offsetof( Derived2 , y) << "\n";
    std::cout << "Offset of z in Derived2 = " << offsetof( Derived2 , z) << "\n";

根据文本 Derived2 应该(?)大小为 16 个字节(假设是 32 位机器),但在 gcc 上我得到 12 个字节。然而,在 Visual Studio 上,它的大小正确(?)报告为 16 个字节。这是一个 gcc 回归错误还是标准没有定义的东西?

编辑

Stanley Lippman 确实使用了offsetof 宏。这是我做的。

【问题讨论】:

我只想说gcc 在填充方面比visual studio 做得更好。关于对象应该如何表示,没有标准的说法。这取决于实施。 您正在阅读 1996 年的版本,那是两个 十年 前,甚至比 C++ 的第一个标准版本发布早两年。尝试查找最新版本;不要太害羞而实际购买适当的教育材料。 我相信 GCC('s ABI) 不必要地在桌面上留下了优化空间。在 64 位和 32 位 x86 上,所有三个类都可以轻松地具有相同的大小 8,方法是将其布局为 4+1+1+1+padding。不过,我认为 Itanium ABI 不允许这样做。 检查 link 以了解填充规则是否适用于您的代码。 【参考方案1】:

offsetof 只能用于标准布局 类型。由于Derived1Derived2 都没有标准布局,因此您的行为是未定义的。

除此之外,C++ 标准并没有对非静态数据成员的布局做出任何特别的承诺,因此如果一个布局与您对另一个布局的期望不符,这并不是真正的“错误”。

【讨论】:

令李普曼失望!以 UB 为例,假设 x 的填充量!为他辩护,这本书写于 1996 年…… 提供的代码似乎很标准。我猜想使用offsetof 的问题只出现在多重继承和虚拟继承中。 @Arunmu:不,Kerrek 是对的;这些类不符合 standard-layout 的定义。阅读§9/7。 @LightnessRacesinOrbit 哦..谢谢!

以上是关于单独继承的派生类的大小的主要内容,如果未能解决你的问题,请参考以下文章

5继承与派生2-访问控制

实验4 类的继承派生和多态

C++类的继承与派生

类的继承和派生

类的继承类的派生类的组合

类的继承和派生