为什么继承的构造函数不能继承默认参数?

Alw*_*ing 15 c++ inheritance c++11

C++ Primer(第5版)第629页指出:

  • 如果基类构造函数具有默认参数,则不会继承这些参数.相反,派生类获取多个继承的构造函数,其中连续省略具有默认参数的每个参数.

这条规则背后的原因是什么?

Nia*_*all 9

鉴于目前的措辞; 我认为这些术语(C++ WD n4527的第 12.9/1 )中有详细说明(但主要是为了避免潜在的歧义);

  1. 避免含糊不清.即如果你开始为自己的构造函数提供匹配的参数,那么这将允许这些构造函数与继承的构造函数不冲突(不明确)
  2. 保持其效果.即客户端代码是什么样的

继承构造类似于代码生成技术("我想要什么我基地有").没有办法指定你得到的构造函数,你基本上都得到它们,因此编译器非常注意不要生成不明确的构造函数.

举例来说;

#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);
}
Run Code Online (Sandbox Code Playgroud)

输出;

Base01
Derived3
Base45

示例代码.


有一个提案说出来n4429在周围的继承构造措辞的改变和使用声明类(如由乔纳森Wakely说明).

鉴于该提案的意图;

...这个提议使继承构造函数就像继承任何其他基类成员一样.

有以下变化(新措辞);

更改7.3.3 namespace.udecl第15段:

using声明将基类的声明带入派生类时......这些隐藏或重写的声明被排除在using声明引入的声明集之外.

然后立即使用一个直接处理构造函数的示例(尽管没有默认参数);

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)
Run Code Online (Sandbox Code Playgroud)

简而言之,虽然可能不是最终的措辞,但似乎意图是允许构造函数与其默认参数一起使用并明确排除隐藏和重写的声明,因此我相信会处理任何歧义.措辞似乎确实简化了标准,但在客户端代码中使用了相同的结果.


Jon*_*ely 6

默认参数不是函数签名的一部分,可以在以后添加,并且在受限范围内添加,这将无法更改派生类的已定义构造函数,例如

// in A.h
struct A {
    A(int, int);
};

// in B.h
#include "A.h"
struct B : A {
    using A::A;
};

// in A.cc
#include "A.h"
A::A(int, int = 0) { }
Run Code Online (Sandbox Code Playgroud)

在文件中,A.cc您可以A使用单个参数构造一个,因为默认参数是可见的,但是在B声明时,默认参数不可见,因此在继承构造函数时不能考虑.我相信这是默认参数得到特殊处理的一个原因.

虽然显然继承构造函数的工作方式可能会发生变化,但默认参数不会得到这种特殊处理,请参阅http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4429.html