Saturday, January 21, 2012

C++ Multiple Inheritance and Class size

While learning or developing any C++ application you must have used the Multiple-inheritance feature provided by language. Lot has been written about it in many places how it do it, how it works and what is what  in multiple inheritance.
There is a very basic thing with respect to multiple inheritance what will be the size of object ?
Consider following hierarchy.
#include<iostream>
using namespace std;
class Base {
     public:
           int a;
};
class X:public Base {
     public:
           int x;
};
class Y:public Base {
     public:
           int y;
};
class Z:public X,public Y
{ };
int main(){
    Z z;
    cout <<"size of z = "<< sizeof(z) <<endl;
return 0;
}
Definitely the output will be 16 considering 32 bit int.
Class Name
Size in Bytes(32 bit integer)
Base
4 ( sizeof(a) )
X
8 ( sizeof(x) + sizeof(Base) )
Y
8 ( sizeof(y) + sizeof(Base) )
Z
16 ( sizeof(X) + sizeof(Y) )
 
In virtual base class there will be only single object and all the classes which derives 
virtual base class requires a pointer to it so that they can access it. 
Consider following hierarchy using virtual inheritance as follow:
#include <iostream>
using namespace std;
class A {
    int a;
};
class B   : public virtual A {
    int b;
} ;
class C : public virtual A {
    int c;
};
class D : public virtual B, public virtual C {
    int d;
};
class E : public B, public C {
    int e;
};
class F : public B, public C{};
class G : public virtual B, public virtual C {};
int main() {
    A a;
    B b;
    C c;
    D d;
    E e;
    F f;
    G g;
    cout << " size of A" << sizeof(A) << endl;
    cout << " size of B" << sizeof(B) << endl;
    cout << " size of C" << sizeof(C) << endl;
    cout << " size of D" << sizeof(D) << endl;
    cout << " size of E" << sizeof(E) << endl;
    cout << " size of F" << sizeof(F) << endl;
    cout << " size of G" << sizeof(G) << endl;
    return 0;
}

Output:
 size of A4
 size of B12
 size of C12
 size of D28
 size of E24
 size of F20
 size of G24
 
Memory Layout:
(gdb) display a
1: a = {a = -6800}
(gdb) display b
2: b = {<A> = {a = 0}, _vptr.B = 0x401188, b = 4196304}
(gdb) display c
3: c = {<A> = {a = 0}, _vptr.C = 0x401168, c = 4197632}
(gdb) display d
4: d = {<B> = {<A> = {a = 0}, 
               _vptr.B = 0x4010c0, b = 6296960}, 
        <C> = {_vptr.C = 0x4010d8, c = 608253861},
        _vptr.D = 0x4010a8, d = 0}
(gdb) display e
5: e = {<B> = {<A> = {a = 6298088}, 
                      _vptr.B = 0x400ff8, b = 6}, 
        <C> = {_vptr.C = 0x401010, c = 4196224}, 
        e = 0}
(gdb) display f
6: f = {<B> = {<A> = {a = 0}, 
               _vptr.B = 0x400f58, b = 4196998}, 
        <C> = {_vptr.C = 0x400f70, c = 4197725}, 
        <No data fields>}
(gdb) display g
7: g = {<B> = {<A> = {a = 0}, 
               _vptr.B = 0x400ea0, b = 6296960},
        <C> = {_vptr.C = 0x400eb8, c = 1}, 
        _vptr.G = 0x400e88}
 
Here is a memory size table for individual class:
 
Class Name
Size in Bytes(32 bit integer) 
A
4 ( sizeof(A) )
B
12 (sizeof(A *) + sizeof(vptr.B) + sizeof(int))
C
12 (sizeof(A *) + sizeof(vptr.C) + sizeof(int))
D
28 (sizeof(A *) + (sizeof(B *) + sizeof(vptr.B)   + sizeof(C *) + sizeof(vptr.C)+ sizeof(vptr.D) + sizeof(int))
E
24 (sizeof(A *) + (sizeof(B *) + sizeof(vptr.B)   + sizeof(C *) + sizeof(vptr.C) + sizeof(int))
F
20 (sizeof(A *) + (sizeof(B *) + sizeof(vptr.B)   + sizeof(C *) + sizeof(vptr.C))
G
28 (sizeof(A *) + (sizeof(B *) + sizeof(vptr.B)   + sizeof(C *) + sizeof(vptr.C)+ sizeof(vptr.D))

Above table explains how the size is calculated in Multiple inheritance. 
*** In some compiler size may vary due to padding done by compiler for memory alignment.

No comments:

Post a Comment