Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why shouldn't the inherited constructor inherit the default arguments?

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

  • If a base class constructor has default arguments, those arguments are not inherited. Instead, the derived class gets multiple inherited constructors in which each parameter with a default argument is successively omitted.

What is the reasoning behind this rule?

like image 417
AlwaysLearning Avatar asked Jul 28 '15 09:07

AlwaysLearning


People also ask

Why default constructor is needed in inheritance?

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.

Why are constructors not inherited?

Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.

Does inheritance inherit constructors?

In inheritance, the derived class inherits all the members(fields, methods) of the base class, but derived class cannot inherit the constructor of the base class because constructors are not the members of the class.

Can a derived class have a constructor with default parameters?

A derived class cannot have a constructor with default parameters. ____ 16. Default arguments can be used with an overloaded operator.


1 Answers

Given the current wording; I think it is specified in these terms (§12.9/1 of C++ WD n4527) for few reasons (but principally to avoid potential ambiguity);

  1. Avoid ambiguity. I.e. if you start to provide your own constructors with matching parameters, this will then allow for these constructors to not conflict (be ambiguous) with the inherited constructors
  2. Maintain the effect thereof. I.e. what would the client code look like

The inheriting constructors is a technique akin to code generation ("I want what my base has"). There is no way to specify which constructors you are getting, you basically get them all hence the compiler much take care to not generate ambiguous constructors.

By way of example;

#include <iostream>
using namespace std;
struct Base {
    Base (int a = 0, int b = 1) { cout << "Base" << a << b << endl; }
};
struct Derived : Base {
    // This would be ambiguous if the inherited constructor was Derived(int=0,int=1)
    Derived(int c) { cout << "Derived" << c << endl; }
    using Base::Base;
};
int main()
{
    Derived d1(3);
    Derived d2(4,5);
}

Outputs;

Base01
Derived3
Base45

Sample code.


There is a proposal out n4429 (as noted by Jonathan Wakely) for a change in the wording around the inheriting constructors and the using declaration for classes.

Given the intent of the proposal;

... this proposal makes inheriting a constructor act just like inheriting any other base class member, to the extent possible.

There is the following change (new wording);

Change in 7.3.3 namespace.udecl paragraph 15:

When a using-declaration brings declarations from a base class into a derived class... Such hidden or overridden declarations are excluded from the set of declarations introduced by the using-declaration.

And immediately follows this with an example that deals directly the constructors (although without default arguments);

struct B1 {
  B1(int);
};

struct B2 {
  B2(int);
};

struct D1 : B1, B2 {
  using B1::B1;
  using B2::B2;
};
D1 d1(0);    // ill-formed: ambiguous

struct D2 : B1, B2 {
  using B1::B1;
  using B2::B2;
  D2(int);   // OK: D2::D2(int) hides B1::B1(int) and B2::B2(int)
};
D2 d2(0);    // calls D2::D2(int)

In short, whilst probably not the final wording, it seems that the intent is to allow the constructors to be used with their default arguments and explicitly excludes hidden and overridden declarations thus I believe taking care of any ambiguity. The wording does seem to simplify the standard, yet yielding the same result w.r.t. it being used in client code.

like image 152
Niall Avatar answered Sep 18 '22 14:09

Niall