Search

11.4 — Constructors and initialization of derived classes

In the past two lessons, we’ve explored some basics around inheritance in C++ and the order that derived classes are initialized. In this lesson, we’ll take a closer look at the role of constructors in the initialization of derived classes. To do so, we will continue to use the simple Base and Derived class we developed in the previous lesson:

With non-derived classes, constructors only have to worry about their own members. For example, consider Base. We can create a Base object like this:

Here’s what actually happens when base is instantiated:

  1. Memory for base is set aside
  2. The appropriate Base constructor is called
  3. The initialization list initializes variables
  4. The body of the constructor executes
  5. Control is returned to the caller

This is pretty straightforward. With derived classes, things are slightly more complex:

Here’s what actually happens when derived is instantiated:

  1. Memory for derived is set aside (enough for both the Base and Derived portions)
  2. The appropriate Derived constructor is called
  3. The Base object is constructed first using the appropriate Base constructor. If no base constructor is specified, the default constructor will be used.
  4. The initialization list initializes variables
  5. The body of the constructor executes
  6. Control is returned to the caller

The only real difference between this case and the non-inherited case is that before the Derived constructor can do anything substantial, the Base constructor is called first. The Base constructor sets up the Base portion of the object, control is returned to the Derived constructor, and the Derived constructor is allowed to finish up its job.

Initializing base class members

One of the current shortcomings of our Derived class as written is that there is no way to initialize m_id when we create a Derived object. What if we want to set both m_cost (from the Derived portion of the object) and m_id (from the Base portion of the object) when we create a Derived object?

New programmers often attempt to solve this problem as follows:

This is a good attempt, and is almost the right idea. We definitely need to add another parameter to our constructor, otherwise C++ will have no way of knowing what value we want to initialize m_id to.

However, C++ prevents classes from initializing inherited member variables in the initialization list of a constructor. In other words, the value of a variable can only be set in an initialization list of a constructor belonging to the same class as the variable.

Why does C++ do this? The answer has to do with const and reference variables. Consider what would happen if m_id were const. Because const variables must be initialized with a value at the time of creation, the base class constructor must set its value when the variable is created. However, when the base class constructor finishes, the derived class constructors initialization lists are then executed. Each derived class would then have the opportunity to initialize that variable, potentially changing its value! By restricting the initialization of variables to the constructor of the class those variables belong to, C++ ensures that all variables are initialized only once.

The end result is that the above example does not work because m_id was inherited from Base, and only non-inherited variables can be changed in the initialization list.

However, inherited variables can still have their values changed in the body of the constructor using an assignment. Consequently, new programmers often also try this:

While this actually works in this case, it wouldn’t work if m_id were a const or a reference (because const values and references have to be initialized in the initialization list of the constructor). It’s also inefficient because m_id gets assigned a value twice: once in the initialization list of the Base class constructor, and then again in the body of the Derived class constructor. And finally, what if the Base class needed access to this value during construction? It has no way to access it, since it’s not set until the Derived constructor is executed (which pretty much happens last).

So how do we properly initialize m_id when creating a Derived class object?

In all of the examples so far, when we instantiate a Derived class object, the Base class portion has been created using the default Base constructor. Why does it always use the default Base constructor? Because we never told it to do otherwise!

Fortunately, C++ gives us the ability to explicitly choose which Base class constructor will be called! To do this, simply add a call to the base class Constructor in the initialization list of the derived class:

Now, when we execute this code:

The base class constructor Base(int) will be used to initialize m_id to 5, and the derived class constructor will be used to initialize m_cost to 1.3!

Thus, the program will print:

Id: 5
Cost: 1.3

In more detail, here’s what happens:

  1. Memory for derived is allocated.
  2. The Derived(double, int) constructor is called, where cost = 1.3, and id = 5
  3. The compiler looks to see if we’ve asked for a particular Base class constructor. We have! So it calls Base(int) with id = 5.
  4. The base class constructor initialization list sets m_id to 5
  5. The base class constructor body executes, which does nothing
  6. The base class constructor returns
  7. The derived class constructor initialization list sets m_cost to 1.3
  8. The derived class constructor body executes, which does nothing
  9. The derived class constructor returns

This may seem somewhat complex, but it’s actually very simple. All that’s happening is that the Derived constructor is calling a specific Base constructor to initialize the Base portion of the object. Because m_id lives in the Base portion of the object, the Base constructor is the only constructor that can initialize that value.

Note that it doesn’t matter where in the Derived constructor initialization list the Base constructor is called -- it will always execute first.

Now we can make our members private

Now that you know how to initialize base class members, there’s no need to keep our member variables public. We make our members variables private again, as they should be.

As a quick refresher, public members can be accessed by anybody. Private members can only be accessed by member functions of the same class. Note that this means derived classes can not access private members of the base class directly! Derived classes will need to use access functions to access private members of the base class.

Consider:

In the above code, we’ve made m_id and m_cost private. This is fine, since we use the relevant constructors to initialize them, and use a public accessor to get the values.

This prints, as expected:

Id: 5
Cost: 1.3

We’ll talk more about access specifiers in the next lesson.

Another example

Let’s take a look at another pair of class we’ve previously worked with:

As we’d previously written it, BaseballPlayer only initializes its own members and does not specify a Person constructor to use. This means every BaseballPlayer we create is going to use the default Person constructor, which will initialize the name to blank and age to 0. Because it makes sense to give our BaseballPlayer a name and age when we create them, we should modify this constructor to add those parameters.

Here’s our updated classes that use private members, with the BaseballPlayer class calling the appropriate Person constructor to initialize the inherited Person member variables:

Now we can create baseball players like this:

This outputs:

Pedro Cerrano
32
42

As you can see, the name and age in the base class were properly initialized, as was the number of home runs in the derived class.

Inheritance chains

Classes in an inheritance chain work in exactly the same way.

In this example, class C is derived from class B, which is derived from class A. So what happens when we instantiate an object of class C?

First, main() calls C(int, double, char). The C constructor calls B(int, double). The B constructor calls A(int). Because A does not inherit from anybody, this is the first class we’ll construct. A is constructed, prints the value 5, and returns control to B. B is constructed, prints the value 4.3, and returns control to C. C is constructed, prints the value ‘R’, and returns control to main(). And we’re done!

Thus, this program prints:

A: 5
B: 4.3
C: R

It is worth mentioning that constructors can only call constructors from their immediate parent/base class. Consequently, the C constructor could not call or pass parameters to the A constructor directly. The C constructor can only call the B constructor (which has the responsibility of calling the A constructor).

Destructors

When a derived class is destroyed, each destructor is called in the reverse order of construction. In the above example, when c is destroyed, the C destructor is called first, then the B destructor, then the A destructor.

Summary

When constructing a derived class, the derived class constructor is responsible for determining which base class constructor is called. If no base class constructor is specified, the default base class constructor will be used. In that case, if no default base class constructor can be found (or created by default), the compiler will error. The classes are then constructed in order from most base to most derived.

At this point, you now understand enough about C++ inheritance to create your own inherited classes!

Quiz time!

1) Let’s implement our Fruit example that we talked about in our introduction to inheritance. Create a Fruit base class that contains two private members: a name (std::string), and a color (std::string). Create an Apple class that inherits Fruit. Apple should have an additional private member: fiber (double). Create a Banana class that also inherits Fruit. Banana has no additional members.

The following program should run:

And print the following:

Apple(Red delicious, red, 4.2)
Banana(Cavendish, yellow)

Hint: Because a and b are const, you’ll need to mind your const’s. Make sure your parameters and functions are appropriately const.

Show Solution

11.5 -- Inheritance and access specifiers
Index
11.3 -- Order of construction of derived classes

30 comments to 11.4 — Constructors and initialization of derived classes

  • Taiwan boy

    Thanks alot, this article saves me!

  • MrAlshahawy

    Your tutorial is more than great, Many thanks for this effort, it is really appreciated, Keep up the good work.

  • sorin

    this is a very good tutorial. thanks Alex!

  • MR.ALEX THANKS ALOT FOR THIS YOUR WONDERFUL TUTORIAL…..

  • manojg

    What is the difference between these defnition of the derived classes constructors:

    class Base
    {
    protected:
    int a, b;
    public:
    Base() {}
    Base(int aa, int bb) { a = aa; b = bb; }
    };

    class Derived : public Base
    {
    protected:
    int c
    public:
    Derived() {}
    Derived(int aa, int bb, int cc) { Base(aa, bb); c = cc; }
    // OR
    Derived(int aa, int bb, int cc) : Base(aa, bb), c(cc) {}
    };

    So, what is the difference between Derived(int aa, int bb, int cc) { Base(aa, bb); c = cc; } and Derived(int aa, int bb, int cc) : Base(aa, bb), c(cc) {}? First definition does not work but they look identical.

    • Tradon

      You can find the answer here.
      http://www.learncpp.com/cpp-tutorial/810-const-class-objects-and-member-functions/

    • Alex

      In the first definition, you’re not doing any initialization. Then inside the constructor body you’re constructing an anonymous object of type Base, which is then discarded. This is why this form doesn’t work.

      In the second form, you’re instructing the Derived constructor to call the Base constructor to initialize the Base members.

  • Tary

    Great tutorial… Helped me so much. Much appreciated. Keep it up.

  • Adam

    Thank you for the tutorial, very useful so far.

  • sdg

    One of the great things about this site is that many of the subjects are explained in ways that are readily understandable. This is certainly not often the case when learning C++. Many times I have had difficulty wrapping my head around a concept and found this site to be very helpful to aid in achieving a better understanding.

  • Tomas Vasko

    Outstanding explanation, simplicity and intelligibility. U should write an whole book 🙂 Basically this whole tutorial is shining example how the education materials for beginners should looks like.  Thank you…

  • 1. In section "initializing base class members":

    "What if we want to set both m_dValue (from the Derived potion of the object) and m_nValue (from the Base portion of the object) when we create a Derived object?"

    "r" is missing in "portion"

    2. "This means every BaseballPlayer we create is going to use the default Person constructor, which will initialize the name to blank and age to 0"

    Under section "Another Example", actually there is no default person constructor. It’s the default values in parameterized Person constructor that saves us.

    • Alex

      1) Thanks for noticing the typo. I guess I drank too many potions when I wrote this. 😛

      2) The term “default constructor” refers to any constructor that can be called with no arguments. The means a constructor that has parameters that are all defaulted is still a default constructor.

  • vish

    Hey alex it is clear that in chaining classes i can initialize the base object in other class object through constructor but if chains got long how will i initialize default constructor to every class? As the last class will not be directly inherited from the first class.
    I hope you understand what i am trying to saying here.
    Thank you.

    • Alex

      Sorry, I am not understanding what you are asking.

      Assuming you have class C inherit from B, and B inherit from A. When you pass parameters to C’s constructor, C can call B’s constructor, which in turn can call A’s constructor. Thus, data can flow from C to B to A, and all levels can be initialized.

  • Matt

    Typo: "Because const variables must be initialized with a value at the time of creation, the base class constructor must set it’s value when the variable is created."

    "it’s" should be "its"

  • Bob

    Thank you very much! this was EXACTLY what I was looking for. Very informative and well written.

  • Darren

    I remember being taught that when using inheritance and inheritance chains, think of the most derived class as being the roof of a house with the base class being its foundation. In order to build a house you have to start from the foundations and go up to the roof; you can’t start at the roof and build down. Similarly when demolishing a house you start at the roof and work down to the foundations; sure you **could** do it the other way but it would be a helluva lot more messy.

  • Srinivas P

    This is a great site to master the topics of C++, khudos to ur valuable efforts.

  • chump

    I think you meant:

    In addition, there is no access function called getCost() in the definition of derived in that code snippet

  • Matt

    In section "Initializing base class members", in the forth code example, you commented:
    "// use Derived(double) constructor".
    I think it should say "use Derived(double, int) constructor".

  • Maybe there’s going to be something about this later, but I tried to implement the quiz solution by having the overloaded << operator be a friend function and access the private members directly and it only worked for those members that weren’t inherited(in this case, apple’s fiber.)

    If you implement it through these getName, getColor and getFiber (which seems like a step backwards) there’s no need to have the overloaded << operator be a friend function, as it only access public functions.

    Just pointing it out.

    In case you’re later going to explain how to have friend functions of children access members inherited from parents, there’s no need to reply. In case you aren’t, why doesn’t

    work? Why does it tell me Fruit::m_name and m_color is private?

    Thanks,

    • Alex

      I think I answer this question in the very next lesson, where I talk more about how access specifiers work with derived classes.

      > Why does it tell me Fruit::m_name and m_color is private?

      Presumably because Fruit::m_name and Fruit::m_color are defined under the private access specifier. If that’s the case, then it’s not a surprise that Apple can’t access the private members of Fruit -- nobody except Fruit can! To do what you’re intending, try changing the members of Fruit to “protected” instead of “private”.

  • Yep, that works. So that’s what protected’s for, huh? Don’t spoil it for me, I guess you’ll be talking about it in future lessons, which I’mdefinitely taking. 🙂

  • Rakesh

    Hi,

    for the below summary

    "When constructing a derived class, the derived class constructor is responsible for determining which base class constructor is called. If no base class constructor is specified, the default base class constructor will be used (if there is one -- if there isn’t, the compiler will error). The classes are then constructed in order from most base to most derived."

    In case there is no default constructor written, since c++ will create a default constructor and initialize the member variables with may be garbage values, why is that the compiler will throw an error if no base class constructor is specified??

    • Alex

      C++ will only create a default constructor if there are no other constructors. So in the case where the base class has a non-default constructor, and the derived class does not call that constructor, you’ll get an error since C++ will not create a default base class constructor for you.

      I’ll see if I can sharpen up the language slightly.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter