In C++, polymorphism does not take place within constructors:
#include <iostream> using namespace std; struct Base { Base() { foo(); } virtual ~Base() {} virtual void foo() { cout << "Base::foo()\n"; } }; struct Derived : Base { void foo() { cout << "Derived::foo()\n"; } }; int main() { Derived(); }
The above program shows Base::foo()
, which is expected for at least the following reasons:
- When the constructor of Base is running, the Derived object isn’t here yet. All methods in Derived class, except constructors, expect the object to be fully constructed unless they are used in the constructors of Derived. In this case, The writer of Derived::foo() has no knowledge that it is used in the constructor of Base.
- Looking at the internal details, polymorphism involves looking for a special object called RTTI (run time type information) inside the object where the method is called with. The constructor of Base can only place the RTTI of Base class in the object, since it does not know what the complete object actually is. It is the job of the constructor of Derived to place the RTTI of Derived class in the object after the Base object is constructed. Therefore, when foo() is invoked in the constructor of Base, the virtual lookup of foo finds the RTTI of Base, hence calls Base::foo().
- In terms of OOP design, polymorphism means to behave differently for different kind of objects. We can think in the way of biological evolution, representating Human as Animalia::Chordata:: Therapsida::Mammalia::Primates::Hominidae::Hominini::Homo::Homo_sapiens. The features common in the lower level of the inheritance tree appear earlier in the process of evolution, therefore, when the lower levels of organisms were created, the features overriden in the higher levels didn’t exist.
However, in Java, I am shocked finding the following piece of code:
class Base { public Base() {foo();} public void foo() {System.out.println("Base.foo()");} } class Derived extends Base { public void foo() {System.out.println("Derived.foo()");} } public class ConstructorPolymorphism { public static void main(String[] args) { new Derived(); } }
outputs Derived.foo(), which is not the same as the equivalent C++ code shown above. It would be a disaster if Derived.foo() depends on some fields to be initialized by the constructor!