Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheriting constructors w / wo their default arguments?

C++ Primer (5th edition) on page 629 states:

  • If a base class constructor has default arguments, those arguments are not inherited.

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.

like image 250
Mugurel Avatar asked Aug 05 '15 11:08

Mugurel


People also ask

How do you inherit a default constructor?

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.

What is constructor with default arguments?

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() .

Does inheritance inherit constructors?

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.

Are default constructors inherited C++?

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.


2 Answers

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.

like image 139
Elohim Meth Avatar answered Oct 23 '22 13:10

Elohim Meth


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.

like image 38
Barry Avatar answered Oct 23 '22 12:10

Barry