4

I have a question about implicit and explicit calls to a base constructor. If we have a class hierarchy like this:

class Person{
    protected:
        std::string m_name;
    public:
        Person(std::string& _name) : m_name(_name){std::cout << "A person is being constructed." << std::endl;}
};

class Baby : public Person{
    private:
        int m_no_of_nappies;
    public:
        Baby(std::string& _name, int& _no_of_nappies) : m_no_of_nappies(_no_of_nappies), Person(_name) {std::cout << "A baby is being constructed." << std::endl ;}

};

According to my lecture notes, a call to 'Baby' in the main, like so:

std::string babyname = "Robert";
int nappies = 5;

Baby baby(babyname, nappies);

Causes the following to happen:

  1. As an explicit call to Person is made in Baby's initialisation list: Baby's initialisation list gets called, and the no_of_nappies is initialised.
  2. Next, a call to Person's constructor is made and Person's initialisation list is called. The m_name is initialised.
  3. Person's constructor body is then called.
  4. Baby's constructor body is finally called.

This makes sense, however, what about if there were implicit calls made to the default constructor of a parent class, like so:

class Vehicle{
    protected:
        int m_no_wheels;
    public:
        Vehicle() : m_no_wheels(0) { std::cout << "A vehicle is being constructed." << std::endl; }
};

class Bicycle : public Vehicle{
    protected:
        bool m_is_locked;
    public:
        Bicycle() : m_is_locked(false) { std::cout << "A bicycle is being constructed." << std::endl; }
};

This is the part that I'm not so sure about. My best guess is that a call to Bicycle bike; in the main has the following effect:

  1. An implicit call is made to Vehicle's default constructor from Bike. Before the Bike's initialisation list is called.
  2. As vehicle doesn't inherit from anything, Vehicle's initialisation list is called where it initialises m_no_wheels to 0.
  3. Vehicle's constructor body is called.
  4. We return to Bicycle and now its initialisation list is called, initialising m_is_locked to false.
  5. Bike's constructor body is called.

Could somebody please explain if my reasoning behind the implicit call is correct?

The main difference, in my opinion, is the fact that with an explicit reference to the base constructor, the child class' initialisation list is always hit first in order to call that base constructor - however, with an implicit call, the top most parent's initialisation list is always hit first.

Thank you, and much appreciated!

Edit: I'm asking specifically if the order changes, depending on an implicit or explicit call to the parent class.

2 Answers2

2

The order of initialization of bases and members is specified in [class.base.init]/11 and you can find a summary here: http://en.cppreference.com/w/cpp/language/initializer_list#Initialization_order

The order of member initializers in the list is irrelevant: the actual order of initialization is as follows:

  1. If the constructor is for the most-derived class, virtual base classes are initialized in the order in which they appear in depth-first left-to-right traversal of the base class declarations (left-to-right refers to the appearance in base-specifier lists)
  2. Then, direct base classes are initialized in left-to-right order as they appear in this class's base-specifier list
  3. Then, non-static data members are initialized in order of declaration in the class definition.
  4. Finally, the body of the constructor is executed

(Note: if initialization order was controlled by the appearance in the member initializer lists of different constructors, then the destructor wouldn't be able to ensure that the order of destruction is the reverse of the order of construction)

The order of initialization is set in stone before any constructors have been defined; the constructor initializer list only affects how bases and members are initialized, not the order in which they are initialized.

Because Person is a base of Baby, it always gets initialized before Baby's member m_no_of_nappies. As part of the initialization of Person, its own members are initialized, and then its constructor body is executed. After Person's constructor's body returns, then m_no_of_nappies is initialized. (Destruction always occurs in the reverse order.) Vehicle is likewise a base of Bicycle, and is initialized first; since there is no mem-initializer for it, the default constructor is called.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • This makes a lot of sense. Just to elaborate: does this mean that even though `Person`'s initialiser and constructor are called before the `m_no_of_nappies` is run - `Baby`'s initialisation list is still hit, in order to call Person's initialiser. So, `Baby` calls Person from within its initialisation list, hence the first thing that's hit is `Baby`'s initialisation list? –  May 19 '15 at 18:49
  • @MuyiwaOlu I'm not really sure I understand your question. I don't know what you mean by "hit". Bases and members are initialized in the prescribed order, and during that initialization, if a corresponding mem-initializer is available, then it is used for the initialization of the named base or member. – Brian Bi May 19 '15 at 18:51
  • @MuyiwaOlu If you didnt list base class constructor ahead of derived class data initialization list you may get warning depends on compiler settings. – Steephen May 19 '15 at 18:52
  • @Brian what I meant by hit was that was `Person`'s initialisation list, and hence body, called from within `Baby`'s initialisation list? –  May 19 '15 at 18:55
  • @MuyiwaOlu An initializer list is not really called from another initializer list. `Baby`'s initializer list determines which of `Person`'s constructors is called, and when that constructor is called, the corresponding initializer list controls initialization of `Person`'s members. – Brian Bi May 19 '15 at 19:03
  • Perfect. That makes complete sense. Thanks. –  May 19 '15 at 19:04
1

§12.6.2 defines how things are initialized:

The order of member initializers in the list is irrelevant: the actual order of initialization is as follows:

  • If the constructor is for the most-derived class, virtual base classes are initialized in the order in which they appear in depth-first left-to-right traversal of the base class declarations (left-to-right refers to the appearance in base-specifier lists)
  • Then, direct base classes are initialized in left-to-right order as they appear in this class's base-specifier list
  • Then, non-static data members are initialized in order of declaration in the class definition.
  • Finally, the body of the constructor is executed (Note: if initialization order was controlled by the appearance in the member initializer lists of different constructors, then the destructor wouldn't be able to ensure that the order of destruction is the reverse of the order of construction)

Summarized for your case (and leaving aside virtual functions):

  1. Base classes in the order of declared inheritance
  2. Members in the order of declaration

Thus the order in the constructor initializer list has no effect.

In the first case you're wrong in this point: Person is a base class of Baby and gets initialized before m_no_of_nappies


Edit: Your question

Baby calls Person from within its initialisation list, hence the first thing that's hit is Baby's initialisation list?

[class.base.init]/10 is probably what you're looking for: you don't really "call" the base class constructor (assuming there's no delegation), it is called by the compiler for you when initializing the derived object.

The compiler sets things up for you to help keeping the order of constructors and destructors right

The reason for ignoring the order of initializers is to preserve the usual FIFO ordering of constructor and destructor calls. Allowing two constructors to use different orders of initialization of bases and members would constrain implementations to use more dynamic and more expensive strategies

Taken from https://stackoverflow.com/a/24287946/1938163

And finally

is the implicit call to the base class (that the compiler makes) done before the Bicycle's initialisation list or after?

Before the rest of the member class initializations as in §12.6.2.

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • Thanks for caring this up for me. What about the second, implicit question? –  May 19 '15 at 18:50
  • @MuyiwaOlu *[class.base.init]/10* is probably what you're looking for. You don't really "call" the base class constructor (assuming there's no delegation), it is called by the compiler for you when initializing the derived object – Marco A. May 19 '15 at 18:54
  • I just wanted to know if the implicit call to the base class (that the compiler makes) was done before the `Bicycle`'s initialisation list or after? –  May 19 '15 at 18:57
  • Before the rest of the member class initializations. – Marco A. May 19 '15 at 18:59
  • Could you add this to the post so I could mark it as answer please? Thank you! –  May 19 '15 at 19:01