I'm keen to know exactly how the classes will be arranged in memory esp. with inheritance and virtual functions.
I know that this is not defined by the c++ language standard. However, is there any easy way to find out how your specific compiler will implement these say by writing some test code?
EDIT:- Using some of the answers below :-
#include <iostream>
using namespace std;
class A {
public:
int a;
virtual void func() {}
};
class B : public A {
public:
int b;
virtual void func() {}
};
class C {
public:
int c;
virtual void func() {}
};
class D : public A, public C {
public:
int d;
virtual void func() {}
};
class E : public C, public A {
public:
int e;
virtual void func() {}
};
class F : public A {
public:
int f;
virtual void func() {}
};
class G : public B, public F {
public:
int g;
virtual void func() {}
};
int main() {
A a; B b; C c; D d; E e; F f; G g;
cout<<"A: "<<(size_t)&a.a-(size_t)&a<<"\n";
cout<<"B: "<<(size_t)&b.a-(size_t)&b<<" "<<(size_t)&b.b-(size_t)&b<<"\n";
cout<<"C: "<<(size_t)&c.c-(size_t)&c<<"\n";
cout<<"D: "<<(size_t)&d.a-(size_t)&d<<" "<<(size_t)&d.c-(size_t)&d<<" "<<(size_t)&d.d- (size_t)&d<<"\n";
cout<<"E: "<<(size_t)&e.a-(size_t)&e<<" "<<(size_t)&e.c-(size_t)&e<<" "<<(size_t)&e.e- (size_t)&e<<"\n";
cout<<"F: "<<(size_t)&f.a-(size_t)&f<<" "<<(size_t)&f.f-(size_t)&f<<"\n";
cout<<"G: "<<(size_t)&g.B::a-(size_t)&g<<" "<<(size_t)&g.F::a-(size_t)&g<<" " <<(size_t)&g.b-(size_t)&g<<" "<<(size_t)&g.f-(size_t)&g<<" "<<(size_t)&g.g-(size_t)&g<<"\n";
}
And the output is :-
A: 8
B: 8 12
C: 8
D: 8 24 28
E: 24 8 28
F: 8 12
G: 8 24 12 28 32
So all classes have got a v-ptr at loc 0 of size 8. D has another v-ptr at location 16. Similarly for E. G also seems to have a v-ptr at 16 although from my (limited) understanding I would have guessed it to have more.
Memory Layout of an Object With Multiple Inheritances & Virtual Function. class X { public: int x; virtual ~X() {} virtual void printX() {} }; class Y { public: int y; virtual ~Y() {} virtual void printY() {} }; class Z : public X, public Y { public: int z; ~Z() {} void printX() {} void printY() {} void printZ() {} };
C++ Concept Map Inheritance is a way of relating two classes so that one class may use another class's members without redefining them (another way is using the friend declaration). A class may be derived from a base class by using the inheritance syntax: class base { ... }; class derived : base { ... };
Inheritance allows us to define a class that inherits all the methods and properties from another class. Parent class is the class being inherited from, also called base class. Child class is the class that inherits from another class, also called derived class.
One way is to print out the offsets of all the members:
class Parent{
public:
int a;
int b;
virtual void foo(){
cout << "parent" << endl;
}
};
class Child : public Parent{
public:
int c;
int d;
virtual void foo(){
cout << "child" << endl;
}
};
int main(){
Parent p;
Child c;
p.foo();
c.foo();
cout << "Parent Offset a = " << (size_t)&p.a - (size_t)&p << endl;
cout << "Parent Offset b = " << (size_t)&p.b - (size_t)&p << endl;
cout << "Child Offset a = " << (size_t)&c.a - (size_t)&c << endl;
cout << "Child Offset b = " << (size_t)&c.b - (size_t)&c << endl;
cout << "Child Offset c = " << (size_t)&c.c - (size_t)&c << endl;
cout << "Child Offset d = " << (size_t)&c.d - (size_t)&c << endl;
system("pause");
}
Output:
parent
child
Parent Offset a = 8
Parent Offset b = 12
Child Offset a = 8
Child Offset b = 12
Child Offset c = 16
Child Offset d = 20
So you can see all the offsets here. You'll notice that there's nothing at offset 0, as that is presumably where the pointer to the vtable goes.
Also notice that the inherited members have the same offsets in both Child and Parent.
Visual Studio atleast has a hidden compiler option /d1reportSingleClassLayout
(starting at ~32:00).
Usage: /d1reportSingleClassLayoutCLASSNAME
where there shall be no whitespace between the compiler switch and CLASSNAME
(obviously replace this with the name of the class you'e interested in).
Create an object of class, cast pointer to it to your machine's word, use sizeof
to find the size of the object, and examine the memory at the location. Something like this:
#include <iostream>
class A
{
public:
unsigned long long int mData;
A() :
mData( 1 )
{
}
virtual ~A()
{
}
};
class B : public A
{
public:
unsigned long long int mData1;
B() :
A(), mData1( 2 )
{
}
};
int main( void )
{
B lB;
unsigned long long int * pB = ( unsigned long long int * )( &lB );
for( int i = 0; i < sizeof(B) / 8; i++ )
{
std::cout << *( pB + i ) << std::endl;
}
return ( 0 );
}
Program output (MSVC++ x86-64):
5358814688 // vptr
1 // A::mData
2 // B::mData1
On a side note, Stanley B. Lippman has excellent book "Inside the C++ Object Model".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With