Reputation:
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:
no_of_nappies
is initialised.m_name
is initialised.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:
m_no_wheels
to 0
.m_is_locked
to false
.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.
Upvotes: 4
Views: 3658
Reputation: 43662
§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):
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.
Upvotes: 1
Reputation: 119632
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:
- 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)
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.
Upvotes: 2