请考虑以下代码:
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)
答案 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) {}
};
毕竟TDerived
和TBase
是不同的类,即使第一个继承了第二个类。