微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么使用虚拟继承时类的大小会以某种不一致模式化的方式增加?

如何解决为什么使用虚拟继承时类的大小会以某种不一致模式化的方式增加?

这是我的理解:

在虚拟继承过程中,:virtual base{} 派生类以及继承的数据成员必须保持 vpointer(跟踪 base 的成员以保持成员的单个实例)和每个继承层次结构虚拟继承的一个 vpointer base 出现在 derived 班级中。

在具有这些知识的代码中:

  • sizeof(B) 和 sizeof(C) 那么应该是 = sizeof(A) + vptr
  • sizeof(D) 应该是 = sizeof(A) + vptr_from_B + vptr_from_C
struct A{
    int i=3,j=1,k=2;
};
struct B: virtual A{};
struct C: virtual A{};
struct D:B,C{};

int main()
{
    std::cout<<"size of class D = "<<sizeof(D)<<"\n";
    std::cout<<"size of class C = "<<sizeof(C)<<"\n";
    std::cout<<"size of class B = "<<sizeof(B)<<"\n";
    std::cout<<"size of class A = "<<sizeof(A)<<"\n";

    return 0;
}

案例 1:

结构 A{};空结构

D = 16,C = 8,B = 8,A = 1

案例 2:

struct A{ int i = 3; };一个整数

D = 24,C = 16,B = 16,A = 4

  • 为什么 B 、C 和 D 有额外的 4 个字节?

案例 3:

struct A{ int i = 3,j = 1; };两个整数

D = 24,C = 16,B = 16,A = 8

  • 现在 B、C 和 D 的大小保持不变,即使 A 的 sizeof A 增加了 4 个字节,...?

案例 4:

struct A{ int i = 3,j = 1,k = 2};三个整数

D = 32,C = 24,B = 24,A = 12

  • 像 Case1 一样,我们又多了 4 个字节?

模式继续。 . . 感觉就像某种零填充来保持虚拟继承的派生类的大小为 8 的倍数,我不知道到底发生了什么以及为什么?

抱歉提早提出愚蠢的问题

解决方法

(Good Reads = this 关于为什么内存对齐很重要,this 关于为什么它对 CPU 很重要)。

  • 简而言之:为了执行性能关键算法,一些 CPU 需要对齐的数据(否则会有 segv 或一些异常错误),如果它没有对齐,那么他们必须执行一些额外的周期来获取正确的偏移量来访问数据从长远来看,这会给性能带来很大的影响。

Case2:

填充到足以使 offset 被其对应的 sizeof(data_member) 整除

struct B & C 看起来像:
enter image description here 下一个偏移量设置为 16,大小为 = 16 个字节

struct D 看起来像:
enter image description here 下一个偏移量设置为 16,大小为 = 24 个字节

  • 重要说明:存储顺序无关紧要,最终大小将相同,因为n = max(sizeof(data_members))final offset 应该可以被n 整除,这里是n = 8。如果在 Case2: 中的 struct B&C 如果我先放 8(B|C::vptr) & offset = 8,那么 4(int) & offset = 12final offset 将填充4 个字节使他可以被 n 整除,最后是 final offset = 24

Case3: 中不需要填充,因为上面 4 个填充的字节是为新的整数成员设置的

Case4

struct D 看起来像:
enter image description here 下一个偏移量设置为 16,大小为 = 32 字节

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。