以下所有操作都将在 GCC 9.1 上使用编译器资源管理器 https://github.com/mattgodbolt/compiler-explorer,在 x86-64 中,使用-O3
.
我有这个代码:
struct Base {
Base() {}
double foo;
int bar;
};
struct Derived : public Base {
int baz;
};
int main(int argc, char** argv)
{
return sizeof(Derived);
}
https://godbolt.org/z/OjSCZB https://godbolt.org/z/OjSCZB
它正确返回16
正如我所期望的,8 个字节foo
,和 4 个字节bar
和 4 个字节baz
。这之所以有效只是因为Derived
继承自Base
所以之后就不需要垫了bar
due to Derived
是包含两者的单一类型Base
and Derived
元素。
我有两个问题,如下:
第一个问题
如果我删除显式构造函数Base() {}
,它开始返回24
, 代替16
。即它在之后添加填充bar
and baz
.
https://godbolt.org/z/0gaN5h https://godbolt.org/z/0gaN5h
我无法解释为什么显式默认构造函数与隐式默认构造函数有什么不同。
第二个问题
如果我随后改变struct
to class
for Base
,它变回返回16
。我也无法解释这一点。为什么访问修饰符会改变结构的大小?
https://godbolt.org/z/SCYKwL https://godbolt.org/z/SCYKwL
这一切都归结为您的类型是否是聚合类型。和
struct Base {
Base() {}
double foo;
int bar;
};
struct Derived : public Base {
int baz;
};
Base
由于构造函数的原因,它不是聚合。当你删除构造函数时,你就做了Base
一个总计,每向基类添加默认构造函数会更改派生类型的 sizeof() https://stackoverflow.com/q/47914612/560648,意味着 gcc 不会“优化”空间,并且派生对象不会使用基础的尾部填充。
当您将代码更改为
class Base {
double foo;
int bar;
};
struct Derived : public Base {
int baz;
};
foo
and bar
现在是私有的(因为默认情况下类具有私有可访问性),这又意味着Base
不再是聚合,因为聚合不允许有私有成员。这意味着我们又回到了第一个案例的工作原理。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)