Consider the following sample code below:
#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;
}
Questions
When
d1obj
is created, the constructors are invoked in the order of derivation : base class constructor is called first and then the derived class constructor. Is this done because of the following reason :In-order to construct the derived class object the base class object needs to be constructed first
?Does
d1obj
contains a base class object ?
I am adding one more question
3) 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?
1-- Yes. And it is logical that way.
Objects of type derived1 are special objects of type base, which means that, as a first thing, they are objects of type base. This is what is constructed first, then "derived1" adds its "specialty" to the object.
2-- It is not a question of containing, it is inheritance. See my paragraph above to better understand this answer.
Yes
Well, conceptually, not really.
d1obj
contains all of the data members that an instance ofbase
would, and responds to all of the member functions that said instance would, but does not "contain" an instance ofbase
: you cannot sayd1obj.base.func()
for instance. If you have, say, overloaded a method your parent declared, you can, however, calld1obj.base::func()
to get its implementation, rather than just callingd1obj->func()
.While it may seem a little like splitting hairs to say that you contain all of the data and methods of your parent without conceptually containing an instance of your parent, this is an important distinction, as you can often attain many of the benefits of direct inheritance by creating a class which contains the "parent" class as member data, like so:
Such a construct allows you to make use of methods already implemented by
base
, as implementation details of your own methods, without having to expose any methods whichbase
declared public but that you don't want to grant access to. An important example of this isstack
, which can contain an instance of another STL container (such asvector
,deque
orlist
), then use theirback()
to implementtop()
,push_back()
forpush()
andpop_back()
forpop()
, all without having to expose the original methods to the user.Yes. Imagine that in the constructor of the derived class, you want to use some members of the base class. Therefore, they need to be initialized. So it makes sense for the base class constructor to be called first.
d1obj
is a base class object. That's what inheritance is. In a way you could say it contains an object of the base class. In memory, the first part of the object will correspond to a base object (in your example you have no virtual functions, if you did, you'd have a pointer to thevftable
ofderived1
first, then your base class members) and after that the members belonging toderived1
.Yes, and yes.
Since your edit, ad 3) The derived class constructor calls the base class constructor as its first act of duty; then all the member object constructors, and finally it executes the constructor body.
Destruction works the opposite way: First the destructor body executes, then the member objects are destroyed (in reverse order of their destruction), and finally the base subobject destructor is called (which is why you always need an accessible destructor in the base class, even if it is pure-virtual).
1) Yes, bases are constructed first, then non-static data members, then the constructor of the derived class is called. The reason is so that the code in the constructor of this class can see and use a fully-constructed base.
2) Yes. You can take this entirely literally: within the memory assigned to the derived class object, there is a region called the "base class sub-object". A derived class object "contains" a base class subobject in precisely the same way that it contains member subobjects for any non-static data members. Actually though, the example given in the question happens to be a special case: the "empty base class optimization". This base class subobject is permitted to be size zero, even though complete objects of type
base
are never size zero.This containment is a low-level thing, though. It's true as others say that conceptually bases are different from members, and the syntax and semantics of the language treat them differently even though the sub-objects themselves are all just parts of the layout of the class.
3) This is an implementation detail. The code in the body of the base class constructor is executed before the code in the body of the derived class constructor, and in effect the derived class constructor is then executed in an invisible compiler-generated try/catch block to ensure that if it throws, the base class is destructed. But it's up to the compiler how to achieve this in terms of what the function entry points in the emitted code actually do.
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.
The compiler always "knows" what bases the class has, because you can only construct an object of a complete type, which implies the compiler can see the class definition, and that specifies the bases. So there's no question of only "finding that it has a base class" when the constructor is entered - the compiler knows that it has a base class, and if the call to the base class constructor is located inside the derived class constructor code, that's just for the convenience of the compiler. It could emit the calls to the base class constructors at every place you construct an object, and for that matter in cases where the derived class constructor can be and is inlined, that's the final effect.