In this video, we'll learn how to invoke base class
constructors and pass in arguments from the derived class.
Remember, since the base part of a derived class must be initialized
first, then we know that some base class constructor must be
invoked to do that initialization.
So in this video, we'll learn how to control exactly which
base constructor will be used.
We can determine which base constructor to be used based on
the arguments that we want to pass to it from the derived class.
So let's see how we can do this.
In this example, we have a base class.
And let's assume that that base class has a no args constructor
and an overloaded constructor that expects a single integer parameter.
Now we have a derived class, which is derived from base.
And the derived class has a constructor that has a
single integer parameter.
We can invoke the base classes overloaded constructor in the
derived constructor's initialization list, as shown in this slide.
That's it. It's pretty simple in clear syntax.
In this case, we're passing the integer x to our base class
constructor when it's invoked.
Following this, we can have initializers for the derived
classes attributes as needed.
Finally, we have the code in the body.
But remember, this code executes after both the base and derived parts of the
derived object have been initialized.
If we don't explicitly invoke the base overloaded constructor.
Then the no args constructor will be invoked automatically since remember
the base part must be initialized.
So let's see the complete example.
Here we see the base class declaration, pretty standard code.
The base class has an integer attribute named value, and
it has two constructors.
The first constructor is the no args constructor, and it
initializes value to 0 and displays base no args constructor.
The second constructor is an overloaded constructor that expects
a single integer parameter, and it initializes value to the integer x and
then it displays int base constructor.
Now let's see the derived class.
The derived class is derived from base using public
inheritance, and it has an integer attribute named doubled value.
It also has two constructors.
The first constructor is the no args constructor.
Note that in its initializer list.
It explicitly invokes the base no args constructor and then initializes
its own double value attribute.
Finally, it displays drive no args constructor.
The second constructor is the overloaded constructor that
expects an integer parameter.
This constructor also invokes the base class overloaded in
constructor in its initializer list.
And then it initializes its own doubled value attribute to 2 times x.
And finally, it displays int derived constructor.
Note that we could have implemented the overloaded constructors
as delegating constructors.
But I wanted to keep the display messages clear so that
we could follow the calls.
So now let's create a few objects and see what's called.
First, let's create a simple base object with no parameters.
In this case, the base no args constructor is called.
In the second example, we're creating a base object and providing an
integer initialization argument.
This will invoke the overloaded int base constructor as we would expect.
Now in the third example, we're creating a derived
object with no parameters.
This will invoke the derived no args constructor, which, in turn, will
invoke the base no args constructor from its initialization list.
Once the base part is initialized, then the rest of the derived
no args constructor executes.
So you can see the output is what we expect.
First, the base no args constructor then the derived no args constructor.
The last example works in the similar way.
We're creating a derived object with an integer initialization argument.
So the derived int derived constructor is invoked, and
then we explicitly invoke the int base constructor from it.
So the first int base constructor executes and then
the int derived constructor.
Of course, all these objects will be destroyed by the destructors
when they go out of scope.
You can see that we have complete control as to which base class
constructors to invoke from our derived class constructors.
So let's head over to the IDE and see this behavior in life code.
Okay, so I'm in the IDE, and I'm in the section 15 workspace
in the BaseClassInitialization project.
This project looks very very similar to the one we
did in the previous video.
However, I've spread out the code a little bit more just so it's easier to
see in the debugger what's going on.
And what I'm doing here is I'm explicitly calling my base class
initializers from my derived class.
So you can see here that I've got a no args constructor in my drive class.
And I'm explicitly calling my base classes no args instructor right here.
Similarly, in the overloaded integer constructor from my drive
class, I'm calling my base classes overloaded integer constructor.
Okay, that way I've got explicit control over how my objects
are being created, not just my part but my base part as well.
So let's run through some examples.
We won't do the base ones because those haven't changed at all.
We'll just worry about the derived ones.
So in this case let's create a derived object, and we'll
call it d, and we'll provide no initialization information here.
So we'll run the debugger and step through it.
So we're here on line 40, and we're just about to
create that derived object d.
Again, I've got no initialization information.
So I expect my no args derived constructor be
called right here on line 26.
And if I step through it, you can see that, that's exactly where I'm at.
But now in this case, I'm explicitly invoking my base class constructor
also the no args constructor, and I'll scroll up just a little bit so it's
going to be right there on line 11.
So what's going to happen now is and it's important to
understand the order here.
Before my attributes are initialized, right, doubled value is my attribute
right here I'm a derived class.
Before my attributes were initialized, before the body of the derived
constructor is initialized, the base part of me will be initialized.
So in this case, when I step through, you'll see that transfers
control up to here on line 11.
And the base no args constructor is called it'll set that value right
here in the base to 0, and it will display base no args constructor.
Then I come back to where I left off, initialize double value to
zero, and you can see that that will indeed be 0 here, now they're
both 0, right, the value in the base as well as the double value
that just got initialized to 0 right here in the initializer list.
Then we display derived no args constructor, and
our object is constructed.
So when it goes out of scope, the destructors will be
called in the reverse order.
So let's do that.
You can see right here the derived destructor is being called, and that
executes, and then we come up to here and execute our base destructor right
here, and we'll display that as well.
Okay, so there you go.
That's a real simple example of how we can invoke our
base class initializers.
Now I'll comment this out.
And what we'll do now is we'll do the same thing but we'll do derived d and
we'll use an initializer of a 1000.
So I've moved the breakpoint to this line 41.
And what we'll do now is we'll start the debugger again, and
we'll walk through this example.
So what do we expect in this case.
Well, on line 41, we're creating a d object which is a derived object, and
we're using a 1000 as initializer.
So we expect this constructor right here on line 30 to be
invoked because it expects.
That's the overloaded integer constructor.
So let's step through, and you'll see that that that's exactly what happens.
But now before we initialize our own variables, before we do anything
in the body of the constructor, our base needs to be initialized.
So in this case, I'm explicitly invoking my base class
constructor with the variable x that was passed into me.
So what's going to happen here is this constructor right here
on line 14 will be invoked.
So let me step through that and you can see that's exactly where
we are, the value will be set to x, in this case, a 1000, and then
I'll display the message, then i come back to my derived overloaded
constructor and finish off here.
What just happened was that my doubled value was initialized to 2000.
And I'm just about to display this.
So at this point, my object has been fully initialized.
And if I look at d, you can see that the base part of me is a 1000
and the doubled value part of me is 2000, which is exactly what we
wanted and that's the issue we had in the previous video that we couldn't
get that quite to work that way.
And of course, as I destroyed this object, the derived destructor
gets invoked first and then the base destructor gets invoked,
and our program is complete.
Okay, so there you go.
That's a real simple example of how to initialize the base part of
us when we're using inheritance.
In the next video what we'll do is we'll look at the way
that copy and move constructors and overloaded assignment
operators work with inheritance.