C ++:多继承中类对象的意外大小

时间:2016-12-30 13:06:37

标签: c++ inheritance sizeof

我注意到多重继承中的奇怪行为。让我们看看下面的例子:

#include <iostream>
using namespace std;

struct A {};
struct B : public A { double x; };
struct C : public A, public B {};

int main() {
    cout << "Size of double: " << sizeof(double) << endl;
    cout << sizeof(A) << ", " << sizeof(B) << ", " << sizeof(C) << endl; // gives 1, 8, 16
}

A类型的大小是1(奇怪,但可以接受),B类型的大小等于8(与双重类型相同,这是预期的),但C类型的大小...等于16.这是更奇怪的是,当我试图找到意想不到的变量时,我无法识别它。

struct D { double a, b; };

C c;
auto &d = reinterpret_cast<D&> (c);
d.a = 1;
d.b = 2;

cout << c.x << endl; //gives 2
cout << c.B::x << endl; //gives 2
cout << c.C::x << endl; //gives... 2

cout << d.a << ", " << d.b << endl; //gives 1, 2

我已经通过这种方式在对象中出现了一个完全出乎意料的数据字段,我无法以正常方式访问它。有什么方法可以解释吗?它是C ++编译器的预期行为吗?

BTW,代码是在Visual Studio 2015,64x中编写和编译的,但是当我在g ++(Ubuntu)上编译第一部分时,结果是相同的--1,8,16。

啊,指定我的问题 - 我想存储指定为继承类型的大量数据,这就是为什么我担心无用的保留字节。如果有人有解决方案,我会很高兴听到 - 即使它有一些#define或编译选项。

2 个答案:

答案 0 :(得分:4)

这里没有太多意外:

  1. A中有两个C子对象:第一个由C立即继承,第二个通过B间接继承。这两个子对象需要有不同的地址。
  2. double中的B想要与合适的地址对齐,即必要时会填充以确保它位于8字节边界(通常;没有任何授权)填充或任何此类填充的大小)。
  3. 要创建一个对象数组(定义{{​​1}}报告的大小),对象将独立填充直接sizeof()子对象所在的大小。
  4. 请注意,问题完全存在是因为您有两个相同类型的空基!如果您有另一个也是空的基础,它可以合法地共享A的地址,整个对象大小只有A

答案 1 :(得分:2)

是的,C ++允许空基子对象的大小为0字节,这是调用empty base optimization。但是每个对象都必须有一个唯一的地址,所以sizeof一个空的类实例化就是1个字节。