So, while being in a ctor/dtor
of a base class while doing smth with a derived class and calling member functions (including virtual), whether via this
pointer or not, the function of the relevant class will be called.
How come? Is vtable
pointer of the object being altered somehow during the process? Because, as I may understand it, there is generally a single vtable
pointer in an object unless multiple inheritance is used.
I have the following code to exemplify what I mean:
#include <stdio.h>
class B {
public:
B()
{ printf("B constructor!\n"); f(); g(); }
virtual ~B()
{ printf("B destructor!\n"); f(); g(); }
virtual void f()
{ printf("f() in B!\n"); }
void g()
{ printf("g() in B!\n"); }
void h()
{ printf("h() in B!\n"); }
};
class D : public B {
public:
D()
{ printf("D constructor!\n"); f(); g(); }
virtual ~D()
{ printf("D destructor!\n"); f(); g(); }
virtual void f()
{ printf("f() in D!\n"); }
void g()
{ printf("g() in D!\n"); h(); }
};
int main()
{
D *d = new D;
B *b = d;
delete b;
}
In ctors/dtors, the member functions of created/destructed object is called.
CodePudding user response:
An object is the type that it is... until it isn't.
Per C 's rules, an object's constructors get called in a specific order. Because a derived class instance is a base class instance at all times, the base class instance constructor needs to be called before the derived class instance.
But if that's the case, then what is the object while the base class constructor is called? The derived class constructor hasn't even started, so it doesn't make sense to consider it a derived class instance yet.
So it isn't.
Therefore, during the period of the base class constructor's execution within a derived class's initialization, all virtual
calls work as if that is all the class is: a base class instance. It is not yet an instance of the derived class type, so you cannot yet call any of the derived class's members.
I mean, yes, you can static_cast
to the derived class instance, but using such a pointer yields undefined behavior, since you're accessing an object of a derived class type before that type has been initialized.
The reverse happens in destructors. The derived class destructor gets called first, then base classes. But after the derived class destructor is finished... the object is no longer a derived class instance. So any virtual
calls in base class destructors go to the base class methods.
In vtable-based implementations, this behavior is implemented by changing the vtable pointer between constructors/destructors at various points during initialization. The base class constructor sets the vtable to point at the base class vtable. When the derived class destructor starts, it sets the vtable to point to the derived class vtable.