Since C++ is based on C, and C is a direct language that does not attempt to hide anything from the programmer, C++ also has simple rules that the programmer can learn and employ. For instance, when objects are stored in memory, it is possible for the programmer to directly access the memory region and interact with the object, without the knowledge of the compiler! Some of the possibilities include:
- It is possible to access even the private and protected data members of the object!
- It is possible to access the data members of the base class, or it’s base class, any number of levels up the chain of inheritance!
- It is possible to invoke member functions of that object without the compiler being aware!
We will now see the rules that govern organisation of objects in memory.
Member functions are shared by objects of the class, and are hence stored in a different location away from the memory allocated to the object, though the object can invoke the virtual member functions using function pointers (discussed later). The size of an object is thus the sum of the sizes of it’s individual data members.
Let A
be the name of a class, whose data members are collectively indicated as A'
. The diagram shows how an object of class A
looks like.
The order of the data members in memory is defined by the order in which they are defined in the class. Note that the access specifiers (private, public and protected) have no role to play here! The data members are stored regardless of their access modifiers.
class A { int x; public: int y; void f(); protected: char z; void g(); public: double a, b; };
For the class definition above, observe how the object is stored in memory. All it’s data members are picked up one by one in the order it was found in the class, irrespective of the access specifier, and the member functions are skipped.
The static data members are meant to be shared by all objects of the class, and it does not make sense for it to be stored as part of every single object.
class A { int x; public: static int y; void f(); protected: static char z; void g(); public: double a, b; };
The static variables y
and z
are not part of the object storage in memory!
The compiler cannot deal with data items whose size is 0 bytes! Therefore, the minimum size of an object will always be 1 byte, even if that requires a dummy byte to be allocated for each object!
class A { int a; }; class B: public A { int b; }; class C: public B { int c; };
The data members of class A
comes first, followed by class B
, followed by class C
, honouring the order of inheritance.
A polymorphic class is one that has virtual functions. A class that derives from a polymorphic class is also automatically polymorphic, regardless of what it contains.
In order to implement late binding (that’s what virtual functions are all about, by the way), objects of polymorphic classes will contain a pointer to the v-table, and this pointer is typically called the vptr (for virtual table pointer), regardless of the actual name that the compiler uses for it. This pointer will require additional memory within the object.
class A { int a; virtual void f1(); virtual void f2(); void f3(); };
The class A
contains virtual functions f1
and f2
, and hence is polymorphic. Thus, all objects of this class will contain vptr
in addition to the defined data members.
If a class derives from 1 polymorphic class, it will have 1 copy of the vptr. If a class derives from 2 polymorphic classes, it will have 2 different copies of the vptr. The number of copies of vptr therefore, as per this rule, is the number of polymorphic base classes. If the number of polymorphic base classes is 0, then the existence of 1 copy of vptr depends on whether this class is polymorphic or not!
class A { int a; virtual void f1(); }; class B { int b; virtual void f2(); }; class C { int c; void f3(); }; class D: public A, public B, public C { int d; virtual void f4(); };
Classes A
and B
are polymorphic while class C
is not. Thus, there will be one vptr
each from class A
and B
, but none from class C
. Class D
does not have a vptr
of it’s own because it does not “start” the polymorphic class chain!
class A { int a; virtual void f1(); }; class B: public A { int b; virtual void f2(); }; class C: public A { int c; virtual void f3(); }; class D: public B, public C { int d; virtual void f4(); };
Base classes B
and C
are both polymorphic, and hence will add a vptr
each to class D
.
class A { int a; virtual void f1(); }; class B: public virtual A { int b; virtual void f2(); }; class C: public virtual A { int c; virtual void f3(); }; class D: public B, public C { int d; virtual void f4(); };
B
and C
are polymorphic classes and will add a copy of vptr
. A
is a polymorphic virtual base class, and adds a vptr
of its own.
Related Articles
No user responded in this post