美文网首页
c/c++补完计划(四): 字节对齐和虚继承

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

作者: sean_depp | 来源:发表于2020-07-22 23:50 被阅读0次

前言

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

结构体大小

先来看个基础的:

#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字节对齐.
然后你会说, 就这?

类大小

那么下面这个呢?

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.

那么继承一下呢?

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, 多一个虚指针. 不对, 这里只有一个虚指针, 继承来的, 指向自己的虚表. 所以如果面试官问你, 为什么基类指针可以动态调用子类函数, 你就可以从虚指针来作答.

虚继承

如果是菱形继承怎么办?

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继承.
如果变化下, 改成虚继承. 先来看输出:

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.

相关文章

网友评论

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

      本文链接:https://www.haomeiwen.com/subject/ingxlktx.html