C ++ POD结构继承?是否有关于派生成员的内存布局的保证

时间:2014-03-14 12:01:11

标签: c++ inheritance pod

让我们说,我有struct RGB,我想创建struct RGBA,继承RGB

struct RGB {
    unsigned char r;
    unsigned char g;
    unsigned char b;
};

struct RGBA: RGB {
    unsigned char a;
};

两者都将用于读取未压缩的图像数据:

RGBA *pixel=static_cast<RGBA *>(image->uncompressed_data);

问题:关于struct RGBA的内存布局,这是否安全?有人保证:

  • unsigned char a位于RGB struct之前(不是之前)
  • struct RGBstruct RGBA的参数之间没有填充?

#pragma pack会在这里提供帮助吗?它是继承期间内存布局的全部内容。

4 个答案:

答案 0 :(得分:15)

不,布局无法保证。唯一的保证是标准布局类;这类课程的一个条件是它

  

在大多数派生类中没有非静态数据成员,并且最多只有一个具有非静态数据成员的基类,或者没有包含非静态数据成员的基类

换句话说,所有数据成员必须属于同一个类,而不是多个。

答案 1 :(得分:9)

对于派生成员的内存布局有 NO 保证,并且演员安全。

由于你有继承,也可能有填充,这是琐碎。

§9课程

  

1 POD struct109是既是普通类又是标准布局类的类,并且没有非POD结构,非POD联合类型的非静态数据成员(或这些类型的数组)。类似地,POD联合是一个既简单的类又是标准的布局类的联合,并且没有非

std::is_pod<RGBA>也不是POD

std::cout << std::boolalpha;
std::cout << std::is_pod<RGBA>::value << '\n';

结果是假的。见live demo

答案 2 :(得分:2)

检查填充很容易:打印sizeof(RGB)sizeof(RGBA)。如果它不是3个相应的4那么结构被填充,你需要将其删除。

至于成员a是否在b之后,您可以使用offsetof来检查每个成员的偏移量。如果a的偏移量大于b的偏移量,则a后面的b会直接出现。{/ p>

答案 3 :(得分:0)

正如这里所有先前的答案已经指出的那样:标准不保证它。但是,如果您仍然需要 POD 的这种继承(派生类实际上不再是 POD),您至少可以通过使用 static_assert 验证当前编译器的行为是否符合要求。如果你切换到另一个行为不同的编译器,那么你至少应该得到编译器错误。不过,如果您的代码应该易于移植,这可能是不好的做法。

我还建议使用编译器变量属性 __attribute__((packed)) 来声明您的 POD 结构并使用 <cstdint>。这对例如有效GCC,但也可能因您使用的编译器而异。

#include <cstdint>

struct __attribute__((packed)) RGB {
    uint8_t r;
    uint8_t g;
    uint8_t b;
};

struct __attribute__((packed)) RGBA : RGB {
    uint8_t a;
};

static_assert( sizeof(RGB) == 3u, "Unexpected size" );
static_assert( sizeof(RGBA) == 4u, "Unexpected size" );