I am new to C++ programming language, i have a confusion about order of calling the constructor in inheritance. my question is even though the constructor and destructor are not inherited by derived class why the base class constructor will call when i create a derived class object.
The purpose of a constructor is to define how the data members should be initialised. Since a derived class inherits the data members from the base class, any constructor of the derived class must define not only how to initialise the data members that are specific to the derived class, but also those coming from the base class.
The natural way to do this (and required by the C++ Standard) is by calling a base class constructor. If you don't include a specific constructor call in the initialization list for your derived-class constructor, the default constructor of the base class will be used to initialise the base-class members.
struct base
{
int _i; // a data member
base():_i(0) {} // default constructor
base(int i):_i(i) {} // special constructor
};
struct derived : base
{
int _j; // a data member specific to the derived class
derived(int i, int j):_j(j) {} // user-defined constructor for the derived class
};
The example above illustrates how the derived-class constructor can initialise its member _j, but the member _i, coming from the base class, must be initialised using a base-class constructor.
The way it's written above, the default constructor base::base() will be automatically called by the compiler, i.e. _i will be initialised to 0.
But you can change that behaviour by including a call to a specific constructor:
struct derived : base
{
int _j;
derived(int i, int j):base(i),_j(j) {} // user-defined constructor for the derived class
};
The order of the constructor calls is: First constructor calls of the base class, then initializers for the derived-class specific members. This is only natural because the derived class, in a sense, is an extension of the base class, and it makes sense to regard the base-class part of the derived-class object as being there first.
Related
In C++ (inheritance subject) I read:
A derived class automatically has a default constructor, a copy
constructor, and an assignment operator, like any other class. The
compiler-generated default constructor calls the base class default
constructor
But on the other hand:
The base class constructors are not inherited We must explicitly
define any constructors the derived class needs
1) what does it mean to inherit a constructor?
2) isn't what is written above a contradiction?
I hope to add some examples if possible to help me understand.
"The base class constructors are not inherited" means that any constructor defined in a class Base is not available for a derived class Derived unless it is re-defined in Derived. This is also valid for the default constructor. But, "A derived class automatically has a default constructor" says that the compiler will automatically generate a default constructor, just as it does for every class. So the compiler will re-define a default constructor in a derived class; it is still not inherited.
The only thing is that "We must explicitly define any constructors the derived class needs", if there is no context under which this statement shall hold, seems wrong. There are definitely constructors available in a derived class that have not been defined explicitely. This can be shown easily by defining a derived class without any explicit constructor:
struct Base {
Base () { std::cout << "in default constructor of Base; not inherited, but still called." << std::endl; };
};
struct Derived : public Base {
// no explicitly defined constructor...
};
int main() {
Derived d;
}
Output:
in default constructor of Base; not inherited, but still called.
So I'd tend to say that the statement "... We must explicitly define any constructors the derived class needs" you cited is either not precise, not shown in full context, or wrong.
struct s {
s() : s_str("my string") {}; // default constructor
std::string s_str;
};
struct d : s {
std::string d_str;
};
If d didn't have any members that needed construction, the default constructor would simply construct s with s::s() which superficially looks like inheritance (and could be implemented that way). But when you add data members to the derived class, that won't work.
The default constructor for s constructs s_str with the text "my string".
If s::s() was inherited in d it wouldn't know about d_str, so wouldn't construct it. So it's not inherited.
Instead, the compiler generates a default constructor for d that constructs d_str with the default constructor for std::string and constructs the s base with s::s().
I've got following program:
#include<iostream>
using namespace std;
struct Base01{
int m;
Base01():m(2){}
void p(){cout<<m<<endl;}
};
struct Derived01:public Base01{
Derived01():m(3){}
};
struct Derived02:virtual public Base01{
Derived01():m(4){}
};
struct my: Derived01,Derived02{
my():m(5){}
};
int main(){
return 0;
}
Both gcc/clang reports compilation error.
I just wish to know what's the language design consideration here, why derived class can only call base class ctor in initialization list, but cannot use base class members directly?
What you do in the constructor initializer list is initialization. It is something that has to be done only once in the lifetime of the object. In general case, that's what starts the objects lifetime.
Base class's constructor (which finished working before your derived class's constructor-proper became active) has already initialized all direct subobjects of the base class. It has already started their lifetimes. If you attempt to reach-in and initialize a direct subobject of base class from the derived class's constructor, that will obviously be the second initialization of the same object. This is completely unacceptable in C++. The language design generally does not allow you to initialize something the second time.
In your case the subobject in question has fundamental type int, so it is hard to see the harm in such "re-initialization". But consider something less trivial, like an std::string object. How do you suggest the derived class should "undo and redo" the initialization already performed by the base class? And while formally it is possible to do it properly, constructor initializer lists are not intended for that purpose.
In general case doing something like that would require a language feature that would allow user to tell base class's constructor something along the lines of "please, leave this subobject of yours uninitialized, I will reach-in and initialize it later from the derived class". However, C++ does not provide users with such capability. A vaguely similar feature exists in virtual base class initialization, but it serves a very specific (and different) purpose.
The proper way to do this in C++ is to pass that value to the base class constructor. Your Base01 class needs an additional constructor that takes the desired value for m. Something like this:
struct Base01{
int m;
Base01():m(2){}
// Added this:
Base01(int mVal) : m(mVal) {}
void p(){cout<<m<<endl;}
};
struct Derived01:public Base01{
Derived01() : Base01(3) {} // Calling base constructor rather than
// initializing base member
};
struct Derived02:virtual public Base01{
Derived01() : Base01(4){} // Same here
};
struct my: Derived01,Derived02{
my(): Base01(5){} // And here.
};
As AnT said, you can't initialize twice--but you can set it up so that things are initialized the way you want in the first place by doing as above.
You certainly can use a base class member in the ctor-initializer list:
struct Base
{
int x;
Base(int x) : x(x) {}
};
struct Derived
{
int y;
Derived() : Base(7), y(x) {}
}
Here, the base member x appears in the initializer for the derived member y; its value will be used.
AnT has done a very nice job explaining why the ctor-initializer list can't be used to (re-)initialize members of base subobjects.
The fundamental language design considerations in this are separation of concerns (avoiding making a base class depend on its derived classes), and that a base class is responsible for initialising its own members (and any bases it has).
A related consideration is that members of the base class don't exist - as far as the derived class constructor is concerned - before the base class constructor completes. If an initialiser list of a derived class was able to reach in and initialise a base class member, then there are two possible consequences
If the base class constructor has not been invoked, its members will not exist when the derived class tries to initialise them.
If the base class constructor has been invoked, the member has been initialised. Initialisation (as distinct from assignment to reinitialise) happens once in the lifetime of an object, so it does not make sense to initialise it again.
Neither of these possibilities really make sense in practice, unless the base class is poorly designed (e.g. its constructors do not properly initialise its members). The sort of machinery needed so they might make sense (e.g. changing order of construction of base classes in a hierarchy, dependent on what member a derived class is trying to initialise) would make compiler machinery more complicated (e.g. being able to both control and track the order of construction of base class members, in case a derived class should choose to reach in), and also mean that the order of construction of classes would depend on derived classs). This would introduce a dependency of the base class behaviour (the means by which it is initialised) on derived classes.
The simpler means is for the base class to provide a constructor that properly initialised the member in question, and for the derived class constructor to invoke that base class constructor in its initialiser list. All of the above (hypothetical) considerations then go away.
While scrolling through SO, I found this question
#include <iostream>
using namespace std;
class base
{
public:
base()
{
cout << "ctor in base class\n";
}
};
class derived1 : public base
{
public:
derived1()
{
cout <<"ctor in derived class\n";
}
};
int main()
{
derived1 d1obj;
return 0;
}
There was this question :- When d1obj is created, the control first reaches the base class constructor and then it goes to the derived class constructor? Or is it the other way round : It first reaches the derived class constructor, finds that it has base class and so the control goes to the constructor in base class?
and the aswer contained the part
When a class has virtual bases it's common for a constructor to result in two different function bodies being emitted - one for use when this class is the most derived type, and one for use when this class is itself a base class. The reason is that virtual base classes are constructed by the most-derived class, to ensure that when they're shared they're only constructed once. So the first version of the constructor will call all base class constructors, whereas the second version will only call constructors for non-virtual bases.
can anyone explain to me this with an example ?
Here is the link for that question
In your example it is the default constructor of derived1 that is responsible for calling the default constructor of base. However, this is only necessary when derived1 is the actual (most derived) object, as in your example
int main()
{
derived1 d1obj; // Most derived object of type `derived1`
// It contains a direct `base` subobject
// Constructor of `derived1` must construct `base` subobject as well
}
But when derived1 is used a base subobject of a larger object
class derived2 : public derived1
{
public:
derived2()
{
cout <<"ctor in derived 2 class\n";
}
};
int main()
{
derived2 d2obj; // Most derived object of type `derived2`
// It contains a direct `derived1` subobject and an indirect `base` subobject
// (through `derived1`)
// Constructor of `derived2` must directly construct both `derived1` subobject and
// `base` subobject
// Which means that constructor of `derived1` subobject should not attempt
// to construct `base` subobject
}
then it is the constructor of derived2 that is responsible for calling both the default constructor of derived1 and the default constructor base. In this case the default constructor of derived1 shall not call the constructor of base, since it will lead to double-construction of base.
To satisfy all of these requirements derived1 will typically have two versions of its default constructor: full version called in your original example and "reduced" version called from derived2 in my example above.
Alternatively, derived1's default constructor can be implemented with a hidden boolean parameter, which will tell it whether to call base's default construictor or not.
"When a class has virtual bases it's common for a constructor to result in two different function bodies being emitted - one for use when this class is the most derived type, and one for use when this class is itself a base class. The reason is that virtual base classes are constructed by the most-derived class, to ensure that when they're shared they're only constructed once. So the first version of the constructor will call all base class constructors, whereas the second version will only call constructors for non-virtual bases."
in this the answerer actually wants to say about a situation common in C++ known as dreaded diamond in multiple inheritance.
to understand just see the most upvoted answer to this link
In C++, what is a virtual base class?
I have the following hierarchy:
Base_class
|
Traits_class
|
Concrete_class
Now the thing is that the data is contained in the Base_class (it needs to be there because the Traits_class has to have access to it. Traits_class is a class template that has different functionality depending on the template parameter passed (so I use partial template specialization for the different classes). Finally, at the lowest level, the Concrete_class is also a class template. I create instances of Concrete_class only.
Now the question is: I have written all constructors, the destructor and I have provided move semantics within the Concrete_class. That means that I do not call the base constructors, but I initialize the state directly in the derived classes.
Can someone point out if there is a problem with this? Only the destructor is declared in the Base_class, and declared as protected. Is there an evident flaw in this design?
Thanks for your insight!
EDIT
So I revised the design following Yakk's comment on the CRTP, and now I have
Traits_class
|
Concrete_class
I have also moved all data to the Concrete_class, and thanks to CRTP I can have access to it in the Traits_class. Something weird happened though, as I couldn't access the data in the Traits_class within the constructor of the Traits_class. I mean, I did access to it, but it seemed as if I was accessing ghost data, because I initialized the members in Traits_class (and even printed within the Traits_class constructor), but then just afterwards the class was empty. So I really don't understand what happened (I was const_casting the Traits_class into the Concrete_class to do this).
In the end, I wrote just static member functions in the Traits_class to initialize the members of the Concrete_class. I guess I could have used protected member functions to do the same thing (because I'm inheriting from Traits_class), but I believe it's the same thing.
If you have any further comments, please let me know. And thanks again for your C++ wisdom.
aa
There is an error in your reasoning. A constructor always initializes all base classes and nonstatic members (technically, a virtual base is initialized by the most-derived type and not by any of the other bases' constructors), so the Base_class will actually be initialized by its compiler-generated default constructor (or compiler-generated copy/move constructors if you're doing a copy or move), which will initialize all data members using their default (or copy/move) constructors. You may later assign those members in the concrete class's constructors, but initialization has already occurred by this point.
Since the base class owns all the data members, it will actually be the base class that initializes all data members when a copy or move occurs. If you write your own copy or move constructor in the most-derived class, you'll either need to invoke the base class's copy/move constructor in your initialization list or the data members will be default-constructed and you'll be forced to use a copy/move-assignment after the fact. This is often inefficient and in some cases may be incorrect. (For example, I've written classes that could be move-constructed, but could not be move-assigned because of slicing issues; if you had such a class in your Base_class as a data member, you couldn't implement move semantics solely in the Concrete_class.)
If you must initialize all the data members from Concrete_class, I recommend you provide a protected constructor in Base_class that takes all data members by value and moves them into its own data members, and provide a perfect-forwarding constructor in Traits_class (or inherit the base's constructor, if you are using a compiler with this support). This allows the concrete class to specify the values for initializing the data members, but allows the base class to do the actual initialization. It also allows the Base_class and Traits_class constructors access to the fully initialized data members (whereas otherwise they can only access the data members in their default-initialized state).
Here's an example:
struct Base_class {
protected:
Base_class( string s ) : s_( move(s) ) { }
~Base_class() = default;
// Request copy/move, since we're declaring our own (protected) destructor:
Base_class(Base_class const &) = default;
Base_class(Base_class &&) = default;
Base_class &operator=(Base_class const &) = default;
Base_class &operator=(Base_class &&) = default;
string s_;
};
template<int>
struct Traits_class : Base_class {
protected:
template<typename... P>
Traits_class( P &&p )
: Base_class( forward<P>(p)... )
{ }
};
template<int I>
struct Concrete_class : Traits_class<I> {
Concrete_class( char c )
: Traits_class<I>( string( I, c ) )
{ }
};
As a side-note, the data doesn't necessarily have to be in Base_class for Traits_class to be able to access it. You could provide access via a protected virtual function if you don't mind the overhead of a virtual function call and if you don't need access within the constructors or destructor (which I'm assuming you don't, since currently the data members don't have their final values until after Concrete_class's constructor runs). Or, to avoid the virtual call overhead, you could use the Curiously Recurring Template Pattern as #Yakk mentions.
== RESPONSE TO EDIT IN ORIGINAL QUESTION ==
The base class's constructor will run before the derived class's constructor, so if the data is stored in the derived class, it will be uninitialized in the base class's constructor (and already reclaimed in its destructor). You can think of a constructor as taking an instance of base class and turning it into an instance of derived class (by initializing the derived part of the class, etc.), and as a special case, the constructor for a class with no base classes turns "nothing" (raw storage) into an instance of the class.
So, when your traits class constructor is running, it isn't yet a concrete derived class. Consequently, accessing the derived class's data members or otherwise using the class as a derived class is illegal. The language even enforces this for virtual functions; if you call a virtual function inside a base class's constructor or destructor, it will call the base version of the function. Example:
#include <iostream>
using namespace std;
struct Base {
Base() { cout << "Base ctor\n"; v(); }
~Base() { v(); cout << "Base dtor\n"; }
protected:
virtual void v() const { cout << "Base::v\n"; }
};
struct Derived : Base {
Derived() { cout << "Derived ctor\n"; v(); }
~Derived() { v(); cout << "Derived dtor\n"; }
protected:
virtual void v() const { cout << "Derived::v\n"; }
};
int main() { Derived d; }
/* Output:
Base ctor
Base::v
Derived ctor
Derived::v
Derived::v
Derived dtor
Base::v
Base dtor
*/
I've known that if B is derived from A, then when I create a new object of B, for example b, the constructor of A will call first. When I destroy the object b, The destructor of B will call first. Then I have a question here, if there're more than one constructor in the Base class, which constructor will call ? and why?
I've write one test program below, I guess it will call the default constructor in the Base class, But I'm not sure if it is just a coincidence?
#include <iostream>
using namespace std;
class A{
public:
A(int i){cout<<"A con with param"<<endl;}
A(){cout<<"A con"<<endl;}
~A(){}
};
class B : public A
{
public:
B(int i){cout<<"B con with param"<<endl;}
B(){cout<<"B con"<<endl;}
~B(){}
};
int main()
{
B b(5);
return 0;
}
I wonder if any boss can tell me the reason or any advise to figure out this problem?
If you write:
B(int i) { cout<<"B con with param"<<endl; }
then constructor A() (without arguments) will be called.
If you write:
B(int i): A(i) { cout<<"B con with param"<<endl; }
then constructor A(int) will be called.
Nothing is by coincidence in programming.
The default constructor is called because, you did not pass int argument explicitly to base class.
For other constructor of base class to be called, the derived class constructor needs to pass the parameters to base class constructor.
So for A(int) to be called, you need to have B():A(some_int) or B(int):A(some_int)
The empty constructor of the parent class will be called unless you call some other constructor explicitly in the initializer list.
EDIT: here is how you call constructor explicitly:
B(int i) : A(i) {
... do stuff ...
}
The order of initialization is a bit more convoluted than that. Technically it starts in the initialization list of the most derived object. That constructor is selected with regular overload resolution from the location where the object is being created. The initialization list of the most derived type constructor lists (either explicitly or implicitly) the constructors of the bases, and again the constructor of the bases will be selected using overload resolution on the call in the initialization list. If the base is not explicitly stated in the initialization list, the compiler will inject a call to the default constructor.
The exact order of construction is also a bit more complex in that the first subobjects that are initialized are the virtual bases, in a particular order (depth-first, left-to-right where left-to-right is the order of declaration in the base classes declaration). Once all virtual bases are initialized, then the direct non-virtual bases of the most derived type are initialized, again in the order of declaration (left-to-right). Once all bases are initialized, the members are then initialized in the order of declaration in the class.
Note that in all cases, the code can explicitly list the subobject in the initialization list, and the constructor listed there will be used, or the default constructor if the entity is not listed.