#include <iostream>
using namespace std;
class Base {
public:
Base() {
cout << "In Base" << endl;
cout << "Virtual Pointer = " << (int*)this << endl;
cout << "Address of Vtable = "
<< (int*)*(int*)this << endl;
cout << "Value at Vtable = "
<< (int*)*(int*)*(int*)this << endl;
cout << endl;
}
virtual void f1() { cout << "Base::f1" << endl; }
};
class Drive : public Base {
public:
Drive() {
cout << "In Drive" << endl;
cout << "Virtual Pointer = "
<< (int*)this << endl;
cout << "Address of Vtable = "
<< (int*)*(int*)this << endl;
cout << "Value at Vtable = "
<< (int*)*(int*)*(int*)this << endl;
cout << endl;
}
virtual void f1() { cout << "Drive::f2" << endl; }
};
int main() {
Drive d;
return 0;
}
The output of this program is
In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C08C
Value at Vtable = 004010F0
In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C07C
Value at Vtable = 00401217
Follow the code, i can see that when i create a Drive object, the Base constructor also run and show the address of virtual pointer same with Drive's virtual pointer: 0012FF7C. The weird thing is that when i dereference that address in both constructors of Base and Drive class, it pointed to different value meaning there are two vtable, one at 0046C08C and another at 0046C07C. Its very difficult to understand in structure of Drive object and also in c langue when 1 pointer point 2 address.
You've just witnessed how your C++ compiler implements the rules set out by the C++ standard. While the Base
constructor is running, any calls to virtual methods need to be dispatched to the Base
implementations, even if Drive
overrides them. To make that happen, your C++ compiler evidently makes the object's vtable pointer point to the Base
vtable. When the Base
constructor finishes and execution continues in the Drive
constructor, the vtable pointer gets updated to point at the Drive
vtable.
That ends up being a convenient way to implement it. The rest of code, where the compiler generates instructions to call virtual methods, doesn't need to change to detect whether the special constructor behavior is required. It can just look in the vtable like always. Changing the vtable pointer is a quick way to change the effective run-time type of the object while the constructors run.
You'll probably find the destructors work in a similar manner, but in reverse. If you construct a Base
object instead of a Drive
object, you'll probably see similar addresses as you do in the Base
constructor of your Drive
object.