Question about virtual inheritance hierarchy

I am facing this problem when solving virtual inheritance. I remember that in a hierarchy of non-virtual inheritance, the subclass object holds the object of its direct superclass. What about virtual inheritance? In this situation, the object of the object obeys the object of its superclass, or simply holds the pointer pointing to the object of its superclass?

By the way, why the output of the following code:

sizeof(A): 8
sizeof(B): 20
sizeof(C): 20
sizeof(D): 36

the code:

#include <iostream>

using namespace std;

class A{
    char k[ 3 ];
    public:
        virtual void a(){};
};

class B : public virtual A{
    char j[ 3 ];
    public:
        virtual  void b(){};
};

class C : public virtual A{
    char i[ 3 ];
    public:
        virtual void c(){};
};

class D : public B, public C{
    char h[ 3 ];
    public:
        virtual void d(){};
};

int main( int argc, char *argv[] ){
    cout << "sizeof(A): " << sizeof( A ) << endl;
    cout << "sizeof(B): " << sizeof( B ) << endl;
    cout << "sizeof(C): " << sizeof( C ) << endl;
    cout << "sizeof(D): " << sizeof( D ) << endl;

    return 0;
}

Thanks in advance. Regards.

+3
source share
5 answers

- , ( = sizeof (object)). -, , . .

sizeof , :

: - 4

:

sizeof(A): 8  ->   1 pointer to vtable (virtual method) 
                 + 3 chars -> 4+3=7 
              -> round up to 8

sizeof(B): 20 ->   8 + 1 pointer to vtable (virtual method) 
                 + 1 offset pointer to virtual base 
                 + 3 chars -> 8 + 4 + 4 + 3 = 19 
              -> round up to 20

sizeof(C): 32 ->  20 + 1 pointer to vtable (virtual method) 
                 + 1 offset pointer to virtual base 
                 + 3 chars 
              -> 20 + 4 + 4 + 3 = 31 // this calculation refers to an older 
              -> round up to 32      // version of the question example 
                                     // where C had B as base class

, , .

,

, :

:

class B  : virtual public A {...};
class C  : virtual public A {...};
class D1 : public B {...};
class D2 : public B, C {...};

D1:

A
B
D1

D2:

A
C
B
D2

B , A

D2 , , D2 - A, - C, B - D2. , , , . , B B - , A .

(D):

sizeof(D): 36 ->   A:3 chars + A:vtable 
                 + B:3 chars + B:vtable + B:virtual base pointer
                 + C:3 chars + C:vtable + C:virtual base pointer
                 + D:3 chars + D:vtable
               =   3 + 4 
                 + 3 + 4 + 4 
                 + 3 + 4 + 4 
                 + 3 + 4 
                 = 36

, , ;-)...

, D- vtable ( ).

, , D vtable 4 ( 8 ):

, , , :

sizeof(D): 36 ->   A:3 chars + A:vtable + A:alignment
                 + B:3 chars + B:vtable + B:virtual base pointer + B:alignment
                 + C:3 chars + C:vtable + C:virtual base pointer + C:alignment
                 + D:3 chars + D:alignment
               =   3 + 4 + 1
                 + 3 + 4 + 4 + 1 
                 + 3 + 4 + 4 + 1
                 + 3 + 1
                 = 36
+5

.

" - , , . , , , . "....

-, . , -. , - ( - , sizeof()) .

.

- , . , -.

. -

, - . , sizeof() (sub), .

-.

HTH

+1

, , . "" "".

: :

#     W    <--- base class
#    / \
#   X   Y  <--- subclasses of W
#    \ /
#     Z    <--- most derived class

Z W. X-->W Y-->W , Z W, Z .

#     W
#    / \   <--- make these two virtual to eliminate duplicate W in Z.
#   X   Y
#    \ /
#     Z

:

class A{...};
class B : public virtual A{...};
class C : public virtual B{...}; // Edit: OP code had this typo when I answered
class D : public B, public C{...};

B, A, . , , - C-->B D-->B, "", :

#   What you have     |     What you want?
#             A       |               A
#            /        |              /
#           /v        |             /
#          /          |            /
#         B           |           B
#        / \          |          / \
#       /v  \         |         /v  \v
#      /     \        |        /     \
#     C       )       |       C       )
#      \     /        |        \     /
#       \   /         |         \   /
#        \ /          |          \ /
#         D           |           D

, , , A, B, - , B-->A , , .

+1

, .
. , ++. ++ , .

, , . iostream, istream ostream basic_ios, iostream istream ostream ( iostream basic_ios ).

, .

What about virtual inheritance? In this situation, the object of the object obeys the object of its superclass, or simply holds the pointer pointing to the object of its superclass?
This implementation is defined. You do not need to know or make any assumptions about this. Suffice it to say that there is a penalty for execution at runtime for virtual inheritance, so you should avoid it when it is not needed.

0
source

For comparison:

struct A {
    void *vptr; // offset 0 size 4 alignment 4
    char k[3]; // offset 4 size 3 alignment 1
    char unnamed_padding; // offset 7 size 1
    // total size 8 alignment 4
};

// MS:
struct base_B {
    void *vptr; // offset 0 size 4 alignment 4
    char j[3]; // offset 4 size 3 alignment 1
    char unnamed_padding; // offset 7 size 1
    A &a_subobject; // offset 8 size 4 alignment 4
    // total size 12 alignment 4

    base_B (&a_subobject) :a_subobject(a_subobject) {}
};

struct B {
    base_B b; // offset 0 size 12 alignment 4
    A a_subobject; // offset 12 size 8 alignment 4
    // total size 20 alignment 4

    B () : b(a_subobject) {}
};

struct base_C {
    void *vptr; // offset 0 size 4 alignment 4
    char i[3]; // offset 4 size 3 alignment 1
    char unnamed_padding; // offset 7 size 1
    A &a_subobject; // offset 8 size 4 alignment 4
    // total size 12 alignment 4

    base_C (&a_subobject) : a_subobject(a_subobject) {}
};

struct C {
    base_C c;
    A a_subobject; // offset 12 size 8 alignment 4
    // total size 20 alignment 4

    C () : c(a_subobject) {}
};

struct D {
    // no new vptr!
    // base_B is used as primary base: b_subobject.vptr is used as vptr
    base_B b_subobject; // offset 0 size 12 alignment 4
    base_C c_subobject; // offset 12 size 12 alignment 4
    char h[3];  // offset 24 size 3 alignment 1
    char unnamed_padding; // offset 27 size 1
    A a_subobject; // offset 28 size 8 alignment 4
    // total size 36 alignment 4

    D (): b_subobject(a_subobject), c_subobject(a_subobject) {}
};

// GCC:
struct base_B {
    void *vptr; // offset 0 size 4 alignment 4
    char j[3]; // offset 4 size 3 alignment 1
    char unnamed_padding; // offset 7 size 1
    // total size 8 alignment 4
};

struct B {
    base_B b; // offset 0 size 12 alignment 4
    A a_subobject; // offset 8 size 8 alignment 4
    // total size 16 alignment 4
};

struct base_C {
    void *vptr; // offset 0 size 4 alignment 4
    char i[3]; // offset 4 size 3 alignment 1
    char unnamed_padding; // offset 7 size 1
    // total size 8 alignment 4
};

struct C {
    base_C b; // offset 0 size 12 alignment 4
    A a_subobject; // offset 8 size 8 alignment 4
    // total size 16 alignment 4
};

struct D {
    // no new vptr!
    // base_B is used as primary base: b_subobject.vptr is used as vptr
    base_B b_subobject; // offset 0 size 8 alignment 4
    base_C c_subobject; // offset 8 size 8 alignment 4
    char h[3];  // offset 16 size 3 alignment 1
    char unnamed_padding; // offset 19 size 1
    A a_subobject; // offset 20 size 8 alignment 4
    // total size 24 alignment 4
};
0
source

Source: https://habr.com/ru/post/1743719/


All Articles