C++ Primer (5th edition) on page 629 states:
I tried this for myself and to me it seems that the derived constructor generated by the compiler also has the same default arguments as the base constructor.
Here's a little test:
#include <iostream>
struct Base
{
Base() = default;
Base(int x_, int y_ = 88, int z_ = 99)
: x(x_), y(y_), z(z_) {}
virtual void debug() const
{ std::cout << "\nx - " << x << ", y - " << y << ", z - " << z << '\n'; }
private:
int x, y, z;
};
struct Derived : Base
{
using Base::Base;
};
int main() {
Base B(1);
B.debug(); // x - 1, y - 88, z - 99
Derived D(5);
D.debug(); // x - 5, y - 88, z - 99
return 0;
}
( You can run this here - http://coliru.stacked-crooked.com/a/26cbb85757c1f021 )
So are we inheriting also the default arguments for a inherited constructor or not?
If not, how come I'm not getting junk for the last 2 members but the same exact values as the default argumuments for the constructor inherited from base?
Also searched on the internet for a clear response about this but found none.
The default constructor in the Person class is not inherited by Employee and therefore a default constructor must be provided in Employee, either automatically by the compiler or coded by the developer. Note that the compiler will also generate a call to the base class default constructor.
A default constructor is a constructor that either has no parameters, or if it has parameters, all the parameters have default values. If no user-defined constructor exists for a class A and one is needed, the compiler implicitly declares a default parameterless constructor A::A() .
Constructors are not inherited. The superclass constructor can be called from the first line of a subclass constructor by using the keyword super and passing appropriate parameters to set the private instance variables of the superclass.
This is one reason constructors aren't inherited. Inheritance means a derived object can use a base-class method, but, in the case of constructors, the object doesn't exist until after the constructor has done its work. I understand the constructor is called before object construction is completed.
Your quote from the book is not full.
If a base-class constructor has default arguments (§6.5.1, p. 236), those arguments are not inherited. Instead, the derived class gets multiple inherited constructors in which each parameter with a default argument is successively omitted. For example, if the base has a constructor with two parameters, the second of which has a default, the derived class will obtain two constructors: one with both parameters (and no default argument) and a second constructor with a single parameter corresponding to the left-most, non-defaulted parameter in the base class
So your Derived class will have 3 inherited constructors with signatures:
Derived (int x): Base{x} {}
Derived (int x, int y): Base{x, y} {}
Derived (int x, int y, int z): Base{x, y, z} {}
And so you are not inheriting any default arguments from base class.
Derived D(5);
calls the first of above three constructors and base constructor is called like
Base(5)
Also note that the default, copy, and move constructors are not inherited. These constructors are synthesized using the normal rules. An inherited constructor is not treated as a user-defined constructor. Therefore, a class that contains only inherited constructors will have a synthesized default constructor.
From [class.inhctor]:
The candidate set of inherited constructors from the class X named in the using-declaration consists of actual constructors and notional constructors that result from the transformation of defaulted parameters and ellipsis parameter specifications as follows:
— [...]
— for each non-template constructor of X that has at least one parameter with a default argument, the set of constructors that results from omitting any ellipsis parameter specification and successively omitting parameters with a default argument from the end of the parameter-type-list, and
— [...]
We have two non-template constructors of Base
. The default constructor of Base
introduces the candidate:
Derived() : Base() { }
And the other constructor of Base
introduces one candidate for each successively omitted parameter. Namely:
Derived(int x, int y, int z) : Base(x, y, z) { }
Derived(int x, int y) : Base(x, y) { }
Derived(int x) : Base(x) { }
The default arguments are not inherited - we just get a different constructor for each number of arguments. So Derived(5)
simply calls Base(5)
, not Base(5, 88, 99)
.
The end result is the same - just how we get there is a bit different.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With