C ++,继承的拷贝ctors不起作用?

时间:2016-06-02 08:00:23

标签: c++ c++11

请考虑以下代码:

class TBase {
public:
   TBase();
   TBase(const TBase &);
};

class TDerived: public TBase {
public:
   using TBase::TBase;
};

void f() {
   TBase Base;
   TDerived Derived(Base); // <=== ERROR
}

所以,我有基类和派生类,并希望使用&#34;使用TBase :: TBase&#34;从基类中拉出复制ctor,以便能够以这种方式创建派生类的实例:

   TDerived Derived(Base);

all compilers拒绝这些错误消息

7 : note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'TBase' to 'const TDerived' for 1st argument

为什么呢?我究竟做错了什么?为什么&#34;使用TBase :: TBase&#34;在这种情况下不起作用?

更新 如何解释来自cppreference.com的一段代码?

struct B1 {
    B1(int);
};
struct D1 : B1 {
    using B1::B1;
// The set of inherited constructors is 
// 1. B1(const B1&)
// 2. B1(B1&&)
// 3. B1(int)

3 个答案:

答案 0 :(得分:8)

复制和移动consturctors(以及默认构造函数)永远不会被继承,只是因为标准这样说。所有其他构造函数都是。

对cppreference的评论误导了(1)。标准中的相同评论说:

  

D1 B1中继承的构造函数的候选集

(强调我的)。

然后标准继续说只有D1(int)构造函数实际上是继承的。 D1的复制和移动构造函数被隐式声明为任何其他类,继承。

有关详细信息,请参阅C ++ 14 12.9 [class.inhctor]。

(1)我提交了对cppreference的更改,希望能澄清这一点。

答案 1 :(得分:3)

如果你进一步阅读同一段代码,它会说:

// D1 has the following constructors:
// 1. D1()
// 2. D1(const D1&) 
// 3. D1(D1&&)
// 4. D1(int) <- inherited
};

因此复制文件仍然是复制文件,它接受TDerived类的参数。尽管如此,D1(int)仍会自动生成。

答案 2 :(得分:1)

按照标准 12.6.3 / p1继承构造函数初始化[class.inhctor.init] Emphasis Mine ):

  

调用类型B的构造函数来初始化a的对象时   不同类型D(即,继承构造函数时)   (7.3.3)),初始化就像默认的默认值一样   构造函数用于初始化D对象和每个基类   继承构造函数的子对象,但B除外   子对象通过调用继承来初始化   构造函数。完整的初始化被认为是单一的   功能调用;特别是继承的初始化   构造函数的参数在任何初始化之前排序   D对象的一部分。

因此,构造函数实际上并不是继承的,而是由相应的派生构造函数隐式或显式调用。还要记住,继承的构造函数只是调用基础构造函数,并且不在派生对象中执行任何成员初始化。

为澄清这一点,请考虑以下示例:

struct Base {
  Base(int);
  ...
};

struct Derived : Base {
  using Base::Base;
  ...
};

上面的Derived类定义在语法上等同于:

struct Derived : Base {
  Derived(int i) : Base(i) {}
  ...
};

也就是说,using类中的Derived声明隐式定义了构造函数Derived(int)。此时还要注意,如果构造函数是从多个基类子对象Derived继承的,那么程序就是格式错误。

以同样的方式,你已经得出了逻辑结论,因为我在基类中声明了一个带有using声明的拷贝构造函数:

class TBase {
public:
   TBase();
   TBase(const TBase &);
};

class TDerived: public TBase {
public:
   using TBase::TBase;
};

我会得到以下语法等效Derived类:

class TDerived: public TBase {
public:
   TDerived() : Base() {}
   TDerived(TBase const &other) : Base(other) {}
};

但事实并非如此。您不能“继承”复制构造函数既不是默认构造函数也不是移动构造函数。为什么?因为这就是C ++标准所规定的。

你可以做的是定义一个用户定义的构造函数,它将把一个基类对象作为输入:

class TDerived: public TBase {
public:
   TDerived(TBase const &other) {}
};

毕竟TDerivedTBase是不同的类,即使第一个继承了第二个类。