Virtual tables and memory layout in multiple virtual inheritance

前端 未结 2 669
忘掉有多难
忘掉有多难 2020-11-28 10:30

Consider following hierarchy:

struct A {
   int a; 
   A() { f(0); }
   A(int i) { f(i); }
   virtual void f(int i) { cout << i; }
};
struct B1 : virtu         


        
2条回答
  •  生来不讨喜
    2020-11-28 11:16

    I have pimped your code a bit as follows:

    #include 
    #include 
    
    struct A {
       int a; 
       A() : a(32) { f(0); }
       A(int i) : a(32) { f(i); }
       virtual void f(int i) { printf("%d\n", i); }
    };
    
    struct B1 : virtual A {
       int b1;
       B1(int i) : A(i), b1(33) { f(i); }
       virtual void f(int i) { printf("%d\n", i+10); }
    };
    
    struct B2 : virtual A {
       int b2;
       B2(int i) : A(i), b2(34) { f(i); }
       virtual void f(int i) { printf("%d\n", i+20); }
    };
    
    struct C : B1, virtual B2 {
       int c;
       C() : B1(6),B2(3),A(1), c(35) {}
       virtual void f(int i) { printf("%d\n", i+30); }
    };
    
    int main() {
        C foo;
        intptr_t address = (intptr_t)&foo;
        printf("offset A = %ld, sizeof A = %ld\n", (intptr_t)(A*)&foo - address, sizeof(A));
        printf("offset B1 = %ld, sizeof B1 = %ld\n", (intptr_t)(B1*)&foo - address, sizeof(B1));
        printf("offset B2 = %ld, sizeof B2 = %ld\n", (intptr_t)(B2*)&foo - address, sizeof(B2));
        printf("offset C = %ld, sizeof C = %ld\n", (intptr_t)(C*)&foo - address, sizeof(C));
        unsigned char* data = (unsigned char*)address;
        for(int offset = 0; offset < sizeof(C); offset++) {
            if(!(offset & 7)) printf("| ");
            printf("%02x ", (int)data[offset]);
        }
        printf("\n");
    }
    

    As you see, this prints quite a bit of additional information that allows us to deduce the memory layout. The output on my machine (a 64-bit linux, little endian byte order) is this:

    1
    23
    16
    offset A = 16, sizeof A = 16
    offset B1 = 0, sizeof B1 = 32
    offset B2 = 32, sizeof B2 = 32
    offset C = 0, sizeof C = 48
    | 00 0d 40 00 00 00 00 00 | 21 00 00 00 23 00 00 00 | 20 0d 40 00 00 00 00 00 | 20 00 00 00 00 00 00 00 | 48 0d 40 00 00 00 00 00 | 22 00 00 00 00 00 00 00 
    

    So, we can describe the layout as follows:

    +--------+----+----+--------+----+----+--------+----+----+
    |  vptr  | b1 | c  |  vptr  | a  | xx |  vptr  | b2 | xx |
    +--------+----+----+--------+----+----+--------+----+----+
    

    Here, xx denotes padding. Note how the compiler has placed the variable c into the padding of its non-virtual base. Note also, that all three v-pointers are different, this allows the program to deduce the correct positions of all the virtual bases.

提交回复
热议问题