继承的构造函数的定义(正文)是什么样的?

时间:2015-01-15 06:27:39

标签: c++ c++11 inheriting-constructors

从我对SO和cppreference link

的答案的阅读
  

继承的构造函数等同于用户定义的构造函数,它具有一个空体,并且一个成员初始化列表由一个嵌套名称说明符组成,它将所有参数转发给基类构造

我得出的结论是,以下类DE的行为应该是非常的。

#include <string>
#include <utility>
using namespace std;

class B
{
public:
  B(string&& a) : a(move(a))
  {
  }

  string a;
};

class D : public B
{
public:
  using B::B;
};

class E : public B
{
public:
  E(string&& a) : B(a)
  {
  }
};

string foo()
{
  return "bar";
}

int main()
{
  D d = foo();//This compiles
  E e = foo();//This does not compile
  return 0;
}

E e = foo()正确无法编译,因为B的构造函数只接受string&&。但是,D d = foo()很好。这是为什么? 使用的编译器是clang3.5。

编辑:此外,正如本answer所述,完美的转发习惯用法不是继承构造函数的替代品。那么,身体究竟是什么样的呢?

2 个答案:

答案 0 :(得分:2)

  

但是,D d = foo()会很好。那是为什么?

因为using B::B有效地将临时字符串直接传递给B的构造函数,所以它仍然可以绑定ala &&(即其值类别仍然是 xvalue ),然后进行任何额外的派生类初始化(如果有其他数据成员,VDT等)。由于使用基类构造函数的目的是允许相同的客户端使用,这是非常可取的。

(与E(string&&)形成鲜明对比,其中指定a参数不再被视为传递给B::B的xvalue(到期临时)成熟。)

(如果你还没有,你可能想要看一下(std::forward)[http://en.cppreference.com/w/cpp/utility/forward] ......它有助于完美转发参数)

答案 1 :(得分:2)

关于派生类中继承的构造函数定义的标准的措辞比cppreference描述所暗示的更明确,但后者中的关键短语 转发所有其论点 。换句话说,参数的值类别将被保留,您E的定义不会这样做,因此无法编译。

来自N3337,§12.9/ 8 [class.inhctor]

  

...隐式定义的继承构造函数执行该类的初始化集合,该集合将由用户编写的该类的内联构造函数执行,并带有 mem-initializer-list 其唯一的 mem-initializer 有一个 mem-initializer-id ,用于命名 nested-name-specifier 中指定的基类> using-declaration 和 expression-list ,如下所示,其函数体中的compound-statement为空(12.6.2)。如果用户编写的构造函数不正确,则程序格式不正确。 表达式列表中的每个表达式都是static_cast<T&&>(p)形式,其中p是相应构造函数参数的名称,T是声明的类型p

因此构造函数参数被完美地转发到相应的继承构造函数(std::forward§20.2.3)被指定为返回static_cast<T&&>(p),与之完全相同以上描述)。根据构造函数参数的声明类型,引用折叠按this answer中所述进行。

在您的情况下,[T=string&&]和强制转换再次产生string&&,这可以绑定到B的参数。要在E中匹配该行为,您应该将构造函数重写为

E(string&& a) : B(static_cast<string&&>(a))
{
}