C++:多重继承中 class 对象的意外大小
C++: Unexpected size of class object in multiple inheritance
我注意到多重继承中的奇怪行为。让我们看下面的例子:
#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(与 double 类型相同,这是预期的),但 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++ 编译器的预期行为吗?
顺便说一句,代码是在 Visual Studio 2015 年 64x 中编写和编译的,但是当我在 g++ (Ubuntu) 上编译第一部分时,结果是相同的 - 1、8、16。
啊,说明我的问题 - 我想存储大量指定为继承类型的数据,这就是为什么我担心无用的保留字节。如果有人有解决方案,我会很高兴听到 - 即使它是一些 #define
或编译选项。
是的,C++ 允许空基子对象的大小为 0 字节,这就是调用 empty base optimization。但是每个对象都必须有一个唯一的地址,所以 sizeof
一个空的 class 实例化本身是 1 个字节。
这里真的没有太多惊喜:
- 您在
C
中有两个 A
子对象:第一个直接由 C
继承,第二个由 B
间接继承。这两个子对象需要有不同的地址。
-
B
中的 double
想要对齐到合适的地址,即,如果需要,将进行填充以确保它处于 8 字节边界(通常;没有填充的授权或任何此类填充的大小)。
- 要创建对象数组(定义
sizeof()
报告的大小),将根据直接 A
子对象所在的大小填充对象。
请注意,问题的存在完全是因为你有两个相同类型的空碱基!如果你有另一个也为空的基地,它可以合法地共享 A
的地址,并且整个对象大小将只是 8
.
我注意到多重继承中的奇怪行为。让我们看下面的例子:
#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(与 double 类型相同,这是预期的),但 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++ 编译器的预期行为吗?
顺便说一句,代码是在 Visual Studio 2015 年 64x 中编写和编译的,但是当我在 g++ (Ubuntu) 上编译第一部分时,结果是相同的 - 1、8、16。
啊,说明我的问题 - 我想存储大量指定为继承类型的数据,这就是为什么我担心无用的保留字节。如果有人有解决方案,我会很高兴听到 - 即使它是一些 #define
或编译选项。
是的,C++ 允许空基子对象的大小为 0 字节,这就是调用 empty base optimization。但是每个对象都必须有一个唯一的地址,所以 sizeof
一个空的 class 实例化本身是 1 个字节。
这里真的没有太多惊喜:
- 您在
C
中有两个A
子对象:第一个直接由C
继承,第二个由B
间接继承。这两个子对象需要有不同的地址。 -
B
中的double
想要对齐到合适的地址,即,如果需要,将进行填充以确保它处于 8 字节边界(通常;没有填充的授权或任何此类填充的大小)。 - 要创建对象数组(定义
sizeof()
报告的大小),将根据直接A
子对象所在的大小填充对象。
请注意,问题的存在完全是因为你有两个相同类型的空碱基!如果你有另一个也为空的基地,它可以合法地共享 A
的地址,并且整个对象大小将只是 8
.