In the previous post, we learned how to create a single-level class hierarchy of an arbitrary depth. We created an asset management system, and the top-level class in this system was Asset. We derived several classes from Asset to represent various real-life assets. We also learned that when we instantiate a class at the bottom of the hierarchy, all its super classes get instantiated.
We also learn that every class has a constructor—either the one provided by the compiler by default or a user-defined one. When the class is instantiated, the runtime allocates memory for it and then calls its constructor. The constructor has a special job—to see that the object is built properly. Each class can initialize its own data members. Although a subclass can initialize the members of its superclass (except for private and static members), it is best that we leave this functionality to each individual class involved in the hierarchy so as to maintain tight encapsulation in the classes.
Now, when we instantiate a subclass, it can obviously initialize its own data members; but then who is responsible for initializing the members of its superclass? For this reason, it is essential that every object-creation process calls its superclass constructor to get an opportunity to initialize its own data members. Likewise, calling each of the superclass constructors in the hierarchy right up to the top-level class will ensure that all the data members in the entire object hierarchy can be properly initialized. Therefore, the compiler enforces a constructor call for every superclass of a derived class. Since, an inherited class inherits all the fields and methods of its base class, except for its constructors. The constructors are strictly used by that base class only.
Suppose we have implemented inheritance in an application a few levels deep. Now, when we instantiate a class at the bottom of this inheritance hierarchy, what happens to its parents?
Are the objects of each parent class in the class hierarchy created? If so, are each of these objects initialized properly? Who does the initialization, if any? Understanding the object creation process will answer these questions and any others that may have come to our mind in the discussions so far. With a good knowledge of how objects are constructed, we are able to create objects with any desired state.
In our asset management system from previous posts, we created an inheritance hierarchy consisting of classes—Asset, BankAccount, and SavingsAccount. After instantiating a SavingsAccount class, we called the various setter methods in each of its superclasses to initialize the derived data members of each superclass. If there are many fields, we need to call several setter methods. With an understanding of the object-creation process, we will find a better way to initialize all these derived data members with an implicit call to the constructor of each superclass.