C++ Class Layout
Class Layout:
Only non-static data members will contribute to the size of the class object. If we have static and non-virtual members are not do anything with respect to the size of the class. Let's consider the following example.
class Base {
};
class Data {
public:
static int data_object_counter;
void print_info() {
cout<<"\n Checking the class size";
}
}
Base baseObj;
Data dataObj;
cout<<"\n Size of Base Object :"<<sizeof(baseObj);
cout<<"\n Size of Data Object:"<<sizeof(dataObj);
If we print the size of each class object provides the same. Let's see if we have the same class members inside the class and try to find the size of the class object.
class Reader {
public:
enum { max_object = 100}; /* define 300 as max object count */
static size_t num_of_object;
Reader *readerObjArray[max_object]; // declaring the 300 same objects
size_t size;
};
size of the object class is 808 (depending on the compiler) and if we comment on the size inside the class, then 8 will get reduced. Reader class is basically an empty class, it means the size should be zero. We are creating 100 Reader objects inside the class of pointer type. Hence each pointer holds the 8-byte address space.
Static Data Members, Type Members, and Non-virtual member functions have no effect on class size.
Implementation of Single Inheritance:
If the class has a virtual function, every object of that type contains a pointer to the shared virtual function table.
Other_stuff:code: Let's see what's all there in other_stuff.
The virtual calling sequence is indirect through the object's virtual function table. The call represents as follows.
basePtr->getIntegerNumber();
Translation Looks like: (*(basePtr->vPtr)[0])(basePtr)
r in other words:
MOV R0,R4 #get basePtr into "this" register
LDR R1, [R4, #+0] #get bp->vptr
LDR R1, [R1, #+0] # get vptr[0] (member function address)
MOV LR, RC #set return link
BX R1 # calling member function
Implementation of overriding:
/*
* checking the single inheritance
*/
#include <iostream>
using namespace std;
class Base
{
public:
Base() : _integerNumber(0) {}
virtual int getIntegerNumber();
virtual void setIntegerNumber(int);
private:
int _integerNumber;
};
int Base::getIntegerNumber()
{
return _integerNumber;
}
void Base::setIntegerNumber(int input)
{
this->_integerNumber = input;
}
class Derived : public Base
{
private:
int _IntNumber;
public:
int getIntegerNumber() { return _IntNumber; } // overrides Base::getIntegerNumber()
void displayInteger() { cout << "\n Integer : " << _IntNumber; }
};
class Shape
{
private:
int _x_axis;
int _y_axis;
public:
Shape() : _x_axis(0), _y_axis(0) { cout << "\nShape::Shape()"; }
Shape(int x) : _x_axis(x), _y_axis(x) { cout << "\nShape::Shape(int)"; }
Shape(int x, int y) : _x_axis(x), _y_axis(y) { cout << "\n Shape::Shape(int,int)"; }
int get_x_axis() { return _x_axis; }
int get_y_axis() { return _y_axis; }
};
class Subject
{
private:
string _name;
public:
Subject() : _name("") { cout << "\nSubject::Subject()"; }
Subject(string name) : _name(name) { cout << "\nSubject::Subject(string)"; }
string getShapeName() { return _name; }
};
class ObservedShape : public Shape, public Subject
{
private:
int _calculateArea;
public:
ObservedShape() : Shape(100, 100), Subject("Reactangle") { cout << "\n Observed::Observed()"; }
int getArea() { return (this->get_x_axis() * this->get_y_axis()); }
};
int main()
{
Base *basePtr = new Base();
basePtr->setIntegerNumber(100);
basePtr = new Derived();
basePtr->setIntegerNumber(800); // invoke base call function
cout << "\n Derived:" << basePtr->getIntegerNumber(); // invoke derived class function
// mutliple Inheritance Object
ObservedShape *obs = new ObservedShape();
Shape *shape = obs;
Subject *subj = obs;
cout << "\n X axis : " << obs->get_x_axis();
cout << "\n Y axis : " << obs->get_y_axis();
cout << "\n Area : " << obs->getArea();
cout << "\n Name : " << obs->getShapeName();
// Let compare the object Shape and ObservedShape object
if (obs == shape)
{
cout << "\n Compiler comparision Successful" << endl;
}
// static cast comparision
ObservedShape *obsPtr = new ObservedShape();
Shape *shapePtr = obsPtr; // no delta
Subject *subPtr = obsPtr; // delta
obsPtr = static_cast<ObservedShape *>(shapePtr); // no delta
obsPtr = static_cast<ObservedShape *>(subPtr); // delta
obsPtr = (ObservedShape *)shape;
obsPtr = (ObservedShape *)subPtr;
return 0;
}
Implementation of Multiple Inheritance:
Object with Multiple Addresses:
Recommended by LinkedIn
Note: An object can have more than one valid address.
Static cast under multiple inheritances:
Note: The dynamic_cast operator usually uses a different mechanism and more expensive.
Under multiple inheritances an object may have more than one vptr:
Problem: The existence of multiple addresses introduces a problem: If a pointer to B2 is used to call an overriding D member function, the value of the "this" pointer will be incorrect.
B2 *b2p = new D();
B2p->f2();
Let see check the traditional implementation, one of the early implementation store delta adjustments for the "this" pointer in the virtual table itself.
This approach has the unfortunate property of having to perform the delta arithmetic even when it is not needed.
Superannuated calling sequences: This approach imposed a space and time overhead on all virtual calls even if multiple inheritances are not used.
Example:
Base2 *base2Ptr = get_me_a_Derived();
Base2ptr->print3();
Was translated: (*base2ptr->vptr[1].funcaddr)(base2ptr+vptr[1].delta)
If the object is passed through void* intermediary, that required type information is going to be lost and not able to access any of the pointer information.
Duplicate Subobjects:
If the same base class appears more than once in the class, we will get copies of base object info in complete class object info.
With the virtual base class, we can avoid the above problem. Inherit the classes as virtual and solve the duplicate sub-objects of the class.
Virtual Base classes problems :
Note: virtual base classes are needed to solve some interface-related issues.
Love it!