Case 1
Here we consider the statement:
Base* ptr = new Derived();
These are the effects of the above statement:
Step 1) An object of type Derived
is created on the heap using the default ctor Derived::Derived()
.
Step 2) Before entering the body of the default ctor Derived::Derived()
, the compiler imlicitly calls the default ctor Base::Base()
. Thus we get the output:
Base::constr
Step 3) Next, the statement print()
inside Base::Base()
is encountered. This statement is equivalent to writing:
this->print();
Hence, the print()
function of class Base
is called.
Step 4) Inside the print
member function of Base
, the call statementprintImpl();
is encountered. This statement is equivalent to writing:
this->printImpl();
But note that currently, the construction of the subobject of type Base
is going on. Meaning the Derived
part of the whole object has not yet been constructed. So even though the printImpl
is a virtual member function and the call is made through a pointer, the virtual mechanism is disabled at this point. And thus the this->printImpl()
calls the Base::printImpl
version instead of the derived version of printImpl
. This happened because the derived class has not yet been initialized. Thus we get the output:
Base::printImpl
Step 5) Finally, the body of the default ctor Derived::Derived()
is executed. And hence we get the output:
Derived::constr
Step 6) The pointer ptr
points to the Base
part of the newly created derived object.
Case 2
Here we consider the statement:
ptr->print();
Now, from this pionter's documentation:
When a non-static class member is used in any of the contexts where the this keyword is allowed (non-static member function bodies, member initializer lists, default member initializers), the implicit this->
is automatically added before the name, resulting in a member access expression (which, if the member is a virtual member function, results in a virtual function call).
So, when you wrote:
ptr->print(); //this is equivalent to writing (*ptr).print();
The above statement is equivalent to writing:
(*ptr).print();
This means that the address of the object to which the pointer ptr
points(which is nothing but ptr
itself) is implicitly passed to the implicit this
parameter of the print
member function.
Now, inside the print
member function, the statement containing the call to printImpl()
is equivalent to:
this->printImpl();
according to the quoted statement at the beginning of my answer. And from the same quoted statement, since the member printImpl
is a virtual member function, the expression this->printImpl()
results in a virtual function call, meaning it results in calling the derived class printImpl
function. And hence we get the output:
Derived::printImpl