前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c/c++补完计划(四): 字节对齐和虚继承

c/c++补完计划(四): 字节对齐和虚继承

作者头像
sean_yang
发布2020-07-23 16:34:52
6400
发布2020-07-23 16:34:52
举报
文章被收录于专栏:Sorrower的专栏Sorrower的专栏

前言

猪场最爱考的内容, 亲测.

结构体大小

先来看个基础的:

代码语言:javascript
复制
#include <iostream>

#pragma pack (8)

using namespace std;
struct A {
    char a;
    int b;
    double c;
};

int main() {
    // 1: 13
    // 2: 14
    // 4: 16
    // 8: 16
    cout << sizeof(A) << endl;
}

按理说, char 1个byte, int 4个byte, double 8个byte. 应该是13个字节, 为什么会有别的答案. 甚至没有#pragma pack (v)的情况下都是16. 原因就在于字节对齐. 关于字节对齐为啥存在, 简单来说, 就是数据都是一块一块读的, 不是一个一个. 那么如何得出呢, 其实很简单, 1的情况下, 是多少就是多少. 2的话, 补成第一个大于13的2的倍数, 也就是14, 4的话, 第一个大于13的4的倍数, 也就是16, 以此类推. 而64位默认是8字节对齐. 然后你会说, 就这?

类大小

那么下面这个呢?

代码语言:javascript
复制
class B {
public:
    B(char a, int b, double c) : a(a), b(b), c(c) {}

    static int x;

    virtual void hello() {};
private:
    char a;
    int b;
    double c;
};

你可能会说还是16, 因为函数和静态变量不算在大小内. 你答对了一半, 函数是不算, 但是virtual关键字导致了虚指针的产生, 而我的mac是64位, 指针占8个字节, 所以答案是24.

那么继承一下呢?

代码语言:javascript
复制
class C : public B {
public:
    C(char a, int b, double c, int d) : B(a, b, c), d(d) {}
    
     virtual void hello() {}
private:
    int d;
};

你会说28, 不过注意, 64位默认8字节对齐, 所以是32哦. 你会说, 不对, 这里有virtual, 多一个虚指针. 不对, 这里只有一个虚指针, 继承来的, 指向自己的虚表. 所以如果面试官问你, 为什么基类指针可以动态调用子类函数, 你就可以从虚指针来作答.

虚继承

如果是菱形继承怎么办?

代码语言:javascript
复制
class B {
public:
    B(char a, int b, double c) : a(a), b(b), c(c) {}

    static int x;

    virtual void hello() {};
private:
    char a;
    int b;
    double c;
};

class C : public B {
public:
    C(char a, int b, double c, int d) : B(a, b, c), d(d) {}

    void hello() override {}

private:
    int d;
};

class D : public B {
public:
    D(char a, int b, double c, int d) : B(a, b, c), d(d) {}

    void hello() override {}

private:
    int d;
};

class E : public C, D {
public:
    E(char a, int b, double c, int d1, int d2, int d) : C(a, b, c, d1), D(a, b, c, d2), d(d) {}

    void hello() override {}

private:
    int d;
};

结果64怎么算, 首先B 24, C 28, D 28, E 28 + 28 + 4 = 60, 然后8字节对齐, 64. 如果4字节对齐就是60. 注意, 这里C, D都有虚指针, 被E继承. 如果变化下, 改成虚继承. 先来看输出:

代码语言:javascript
复制
class C : virtual public B {
public:
    C(char a, int b, double c, int d) : B(a, b, c), d(d) {}

    void hello() override {}

private:
    int d;
};

class D : virtual public B {
public:
    D(char a, int b, double c, int d) : B(a, b, c), d(d) {}

    void hello() override {}

private:
    int d;
};

image

是不是懵了, C, D变大了, E变小. 先来看E, 它继承了C, D的独有变量,但是没有继承他们从B得到的, 而是直接从B获取一份内容, 这样就是3个虚指针, B的变量, C和D的变量, 自己的变量, 也就是24+13+4+4+4=49, 8字节对齐, 等于56. 那么40怎么来的? 其实2个虚指针+B的变量+C的变量, 16+13+4=33, 8字节对齐, 40.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 结构体大小
  • 类大小
  • 虚继承
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档