[Question]
Suppose that C is inherited from B and B is inherited from A.
Each class has virtual function(destructor and foo).
This means that all classed have their own VMT(VMT for A, VMT for B and VMT for C).
When constructor and destructor code is executed, how(and when) is VMT pointer is changed for the object?
[How to test]
All constructor and destructor function, Sleep(1000) is added.
When the object is destroyed, launch another thread that call foo function after a specific time(1500 msec).
[Source / C++]
class A { public: A() { printf("A::A\n"); Sleep(1000); } virtual ~A() { printf("A::~A\n"); Sleep(1000); } virtual void foo() { printf("A::foo\n"); } }; class B : public A { public: B() { printf("B::B\n"); Sleep(1000); } virtual ~B() { printf("B::~B\n"); Sleep(1000); } virtual void foo() { printf("B::foo\n"); } }; class C : public B { public: C() { printf("C::C\n"); Sleep(1000); } virtual ~C() { printf("C::~C\n"); Sleep(1000); } virtual void foo() { printf("C::foo\n"); } }; static C* c = NULL; void fooFunc(int sleepTime) { Sleep(sleepTime); c->foo(); // which foo function is called? } int main() { c = new C; boost::thread thread(fooFunc, 1500); delete c; thread.join(); return 0; }
[Output / C++]
A::A
B::B
C::C
C::~C
B::~B
B::foo
A::~A
[Source / Pascal]
program vmt_test; {$APPTYPE CONSOLE} uses Classes, SysUtils; type A = class constructor Create; virtual; destructor Destroy; override; procedure foo; virtual; end; B = class(A) constructor Create; override; destructor Destroy; override; procedure foo; override; end; C = class(B) constructor Create; override; destructor Destroy; override; procedure foo; override; end; TMyThread = class(TThread) protected procedure Execute; override; end; var _c: C; constructor A.Create; begin inherited; WriteLn('A::A'); Sleep(1000); end; destructor A.Destroy; begin WriteLn('A::~A'); Sleep(1000); inherited; end; procedure A.foo; begin WriteLn('A::foo'); end; constructor B.Create; begin inherited; WriteLn('B::B'); Sleep(1000); end; destructor B.Destroy; begin WriteLn('B::~B'); Sleep(1000); inherited; end; procedure B.foo; begin WriteLn('B::foo'); end; constructor C.Create; begin inherited; WriteLn('C::C'); Sleep(1000); end; destructor C.Destroy; begin WriteLn('C::~C'); Sleep(1000); inherited; end; procedure C.foo; begin WriteLn('C::foo'); end; procedure TMyThread.Execute; begin Sleep(1500); _c.foo; // which foo function is called? end; var MyThread: TMyThread; begin _c := C.Create; MyThread := TMyThread.Create(false); _c.Free; MyThread.WaitFor; end.
[Output / Pascal]
A::A
B::B
C::C
C::~C
B::~B
C::foo
A::~A
[Analysys of Pascal]
The object VMT pointer value is set only just one time before creating the object. There is no the object VMT pointer changing in constructor and destructor code.
Call C.Ceate
vmt_test.dpr.104: _c := C.Create; 004112E3 B201 mov dl,$01 004112E5 A1D0084100 mov eax,[$004108d0] // pointer of VMT for C 004112EA E871F8FFFF call C.Create 004112EF A3E0794100 mov [$004179e0],eax
[Analysis of C++]
Whenever constructor and destructor is called, the object VMT pointer value is changed.
A::A()
B::B()C::C()