sizeof most-derived-class

Discussion in 'C++' started by munna, Apr 7, 2010.

  1. munna

    munna Guest

    Considering the classic diamond problem in where we have this
    relationship,
    A
    / \
    B C
    \ /
    D
    and define our classes like the following:

    class A{
    public:
    virtual void f1(){}
    };
    class B: public virtual A{
    public:
    void f1(){}
    };
    class C: public virtual A{
    public:
    void f1(){}
    };
    class D: public B, public C{
    public:
    void f1(){}
    };

    Specifically how the memory-layout for class D-object would be laid
    out (in practice). Or is it so that since the standard doesn't
    mandates any specific layout, compilers are free to have it at their
    discretion? What i understand is that size of class A would be 4 bytes
    (on a 32-bit architecture), sizeof B and C would be 8 bytes (one vptr
    for B/C and one pointer to virtual base class A). How exactly would a
    D object look like?
    munna, Apr 7, 2010
    #1
    1. Advertising

  2. munna

    tonydee Guest

    On Apr 8, 3:04 am, munna <> wrote:
    > Considering the classic diamond problem in where we have this
    > relationship,
    >                                                    A
    >                                                  /    \
    >                                                B     C
    >                                                 \     /
    >                                                    D
    >  and define our classes like the following:
    >
    > class A{
    > public:
    >      virtual void f1(){}};
    >
    > class B: public virtual A{
    > public:
    >      void f1(){}};
    >
    > class C: public virtual A{
    > public:
    >       void f1(){}};
    >
    > class D: public B, public C{
    > public:
    >       void f1(){}
    >
    > };
    >
    >  Specifically how the memory-layout for class D-object would be laid
    > out (in practice). Or is it so that since the standard doesn't
    > mandates any specific layout, compilers are free to have it at their
    > discretion? What i understand is that size of class A would be 4 bytes
    > (on a 32-bit architecture), sizeof B and C would be 8 bytes (one vptr
    > for B/C and one pointer to virtual base class A). How exactly would a
    > D object look like?


    As Victor says, this isn't specified in the Standard, but typically a
    compiler will want D to be a concatenation of a B and C object, as it
    needs to be able to pass a pointer-to-(some-part-of)-D to functions
    accepting B* or C*, and such functions aren't going to want to perform
    some run-time check to see if parts of the B or C object are laid out
    in a different layout used by some derived classes. So, expect sizeof
    D to be sizeof B + sizeof C.

    Cheers,
    Tony
    tonydee, Apr 8, 2010
    #2
    1. Advertising

  3. On Apr 7, 7:25 pm, tonydee <> wrote:
    > On Apr 8, 3:04 am, munna <> wrote:
    > > Considering the classic diamond problem in where we have this
    > > relationship,
    > >                                                    A
    > >                                                  /    \
    > >                                                B     C
    > >                                                 \     /
    > >                                                    D
    > >  and define our classes like the following:

    >
    > > class A{
    > > public:
    > >      virtual void f1(){}};

    >
    > > class B: public virtual A{
    > > public:
    > >      void f1(){}};

    >
    > > class C: public virtual A{
    > > public:
    > >       void f1(){}};

    >
    > > class D: public B, public C{
    > > public:
    > >       void f1(){}

    >
    > > };

    >
    > >  Specifically how the memory-layout for class D-object would be laid
    > > out (in practice). Or is it so that since the standard doesn't
    > > mandates any specific layout, compilers are free to have it at their
    > > discretion? What i understand is that size of class A would be 4 bytes
    > > (on a 32-bit architecture), sizeof B and C would be 8 bytes (one vptr
    > > for B/C and one pointer to virtual base class A). How exactly would a
    > > D object look like?

    >
    > As Victor says, this isn't specified in the Standard, but typically a
    > compiler will want D to be a concatenation of a B and C object, as it
    > needs to be able to pass a pointer-to-(some-part-of)-D to functions
    > accepting B* or C*, and such functions aren't going to want to perform
    > some run-time check to see if parts of the B or C object are laid out
    > in a different layout used by some derived classes.  So, expect sizeof
    > D to be sizeof B + sizeof C.


    Virtual inheritance is involved. I would specifically expect not that.
    For MSVC 2008 on a 32 bit build, I happened to get
    sizeof A == 4
    sizeof B == 8
    sizeof C == 8
    sizeof D == 12

    WHAT FOLLOWS IS NOT PORTABLE. DO NOT RELY ON IT IN PRODUCTION CODE.

    All D objects need to contain a B subobject, a C subobject, and
    exactly one A subobject. As such, it cannot simply put A's members at
    offset 0 in the B subobject and offset 0 in the C suboject. (Think
    about it.) Normally, to convert between a base class pointer and a
    derived class pointer, just a compile time known offset is added (0
    for single inheritance, and zero and nonzero for multiple
    inheritance). For virtual inheritance, the offset to a base class
    subobject is no longer a compile time constant, and it must be looked
    up at runtime, hence this extra "stuff" in the B, C, and D objects.
    Joshua Maurice, Apr 8, 2010
    #3
  4. munna

    tonydee Guest

    On Apr 8, 11:54 am, Joshua Maurice <> wrote:
    > On Apr 7, 7:25 pm, tonydee <> wrote:
    >
    >
    >
    > > On Apr 8, 3:04 am, munna <> wrote:
    > > > Considering the classic diamond problem in where we have this
    > > > relationship,
    > > >                                                    A
    > > >                                                  /    \
    > > >                                                B     C
    > > >                                                 \     /
    > > >                                                    D
    > > >  and define our classes like the following:

    >
    > > > class A{
    > > > public:
    > > >      virtual void f1(){}};

    >
    > > > class B: public virtual A{
    > > > public:
    > > >      void f1(){}};

    >
    > > > class C: public virtual A{
    > > > public:
    > > >       void f1(){}};

    >
    > > > class D: public B, public C{
    > > > public:
    > > >       void f1(){}

    >
    > > > };

    >
    > > >  Specifically how the memory-layout for class D-object would be laid
    > > > out (in practice). Or is it so that since the standard doesn't
    > > > mandates any specific layout, compilers are free to have it at their
    > > > discretion? What i understand is that size of class A would be 4 bytes
    > > > (on a 32-bit architecture), sizeof B and C would be 8 bytes (one vptr
    > > > for B/C and one pointer to virtual base class A). How exactly would a
    > > > D object look like?

    >
    > > As Victor says, this isn't specified in the Standard, but typically a
    > > compiler will want D to be a concatenation of a B and C object, as it
    > > needs to be able to pass a pointer-to-(some-part-of)-D to functions
    > > accepting B* or C*, and such functions aren't going to want to perform
    > > some run-time check to see if parts of the B or C object are laid out
    > > in a different layout used by some derived classes.  So, expect sizeof
    > > D to be sizeof B + sizeof C.

    >
    > Virtual inheritance is involved. I would specifically expect not that.
    > For MSVC 2008 on a 32 bit build, I happened to get
    > sizeof A == 4
    > sizeof B == 8
    > sizeof C == 8
    > sizeof D == 12


    For SunC++ 5.8 and g++ 3.4.3 I get 4, 4, 4 and 8.

    > WHAT FOLLOWS IS NOT PORTABLE. DO NOT RELY ON IT IN PRODUCTION CODE.
    >
    > All D objects need to contain a B subobject, a C subobject, and
    > exactly one A subobject. As such, it cannot simply put A's members at
    > offset 0 in the B subobject and offset 0 in the C suboject. (Think
    > about it.)


    Agreed, but B and C may both embed a pointer to the single A.

    > For virtual inheritance, the offset to a base class
    > subobject is no longer a compile time constant, and it must be looked
    > up at runtime, hence this extra "stuff" in the B, C, and D objects.


    True... via the pointer.

    Cheers,
    Tony
    tonydee, Apr 8, 2010
    #4
  5. munna

    munna Guest


    >
    > Agreed, but B and C may both embed a pointer to the single A.
    >
    > > For virtual inheritance, the offset to a base class
    > > subobject is no longer a compile time constant, and it must be looked
    > > up at runtime, hence this extra "stuff" in the B, C, and D objects.

    >


    If both B and C contains an embedded pointer to the shared base-class
    object, the size would have been 16 for D (which is not the case!)

    The reason my understanding got all muddled up : when i was going
    through the text mentioned in the thread above "Inside Object Model",
    where it says that the memory layout of class B would be so that it
    contains

    1. vptr-b pointing to B's vtable (4 bytes)
    2. pointer to the virtual base class (4 bytes)

    and hence the size of B (and similarly for C) would be 8 bytes. But,
    while composing the D object, the layout is such that it contains two
    portions viz. the shared/invariant region (marked by the shared base
    sub-object) and both B and C contain a pointer to it! ( Chapter 3,
    section 3.4, figure 3.5a) where it says something like this

    1. for class A:
    ----------------
    vptrA
    ----------------

    2. for class B: (and C)
    ----------------
    PointerToA
    ----------------
    vptrB
    ----------------
    Shared object A (this also contains a vptr!!!!)
    ----------------

    3. and finally for class D
    ----------------
    vptrD
    ----------------
    PointerToA
    ----------------
    vptrD
    ----------------
    PointerToA
    ----------------
    Shared object A (this also contains a vptr!!!!)
    ----------------

    So obviously something here is at contradiction!!!
    munna, Apr 9, 2010
    #5
  6. munna

    tonydee Guest

    On Apr 9, 12:56 pm, munna <> wrote:

    [given...

    struct A { virtual void f() { } };
    struct B : public virtual A { void f() { } };
    struct C : public virtual A { void f() { } };
    struct D : public B, public C { void f() { } };
    ]

    > If both B and C contains an embedded pointer to the shared base-class
    > object, the size would have been 16 for D (which is not the case!)
    >
    > The reason my understanding got all muddled up : when i was going
    > through the text mentioned in the thread above "Inside Object Model",
    > where it says that the memory layout of class B would be so that it
    > contains
    >
    > 1. vptr-b pointing to B's vtable (4 bytes)
    > 2. pointer to the virtual base class (4 bytes)
    >
    > and hence the size of B (and similarly for C) would be 8 bytes.


    But the virtual function from A is the only virtual function in B, why
    would a distinct "1." be required? Seems Sun and GNU compilers are
    smart enough to consolidate the above.

    Same goes for D really, but due to the reason I mentioned before -
    wanting discrete, contiguous embedded B and C objects to pass to
    functions expecting them, it's easier to have two pointers to the
    (presumably same) virtual dispatch table.

    [snip]
    > So obviously something here is at contradiction!!!


    Hope that clarifies things.

    Cheers,
    Tony
    tonydee, Apr 9, 2010
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. H.MuthuKumaraRajan
    Replies:
    3
    Views:
    417
    H.MuthuKumaraRajan
    Feb 4, 2004
  2. GRenard
    Replies:
    2
    Views:
    403
    Salt_Peter
    Nov 3, 2006
  3. Replies:
    1
    Views:
    378
    myork
    May 23, 2007
  4. Replies:
    1
    Views:
    369
    Victor Bazarov
    May 23, 2007
  5. cppquester

    sizeof(derived) >= sizeof(base)?

    cppquester, Oct 7, 2011, in forum: C++
    Replies:
    1
    Views:
    298
    Juha Nieminen
    Oct 7, 2011
Loading...

Share This Page