C++,继承的复制因子不起作用

C++, inherited copy ctors does not work?

本文关键字:不起作用 复制 继承 C++      更新时间:2023-10-16

考虑以下代码:

class TBase {
public:
TBase();
TBase(const TBase &);
};
class TDerived: public TBase {
public:
using TBase::TBase;
};
void f() {
TBase Base;
TDerived Derived(Base); // <=== ERROR
}

因此,我有基类和派生类,并希望使用"使用TBase::TBase"从基类中提取副本ctor,以便能够以这样的方式创建派生类的实例:

TDerived Derived(Base);

但是所有的编译器都拒绝使用这些错误消息

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

为什么?我做错了什么?为什么"使用TBase::TBase"在这种情况下不起作用?

UPDATE如何解释以下来自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)

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

关于cppresence的评论具有误导性。标准中的相同评论说:

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

(强调矿)。

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

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


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

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

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

因此,复制ctor仍然是复制ctor,它接受类TDerived的参数。然而,D1(int)是自动生成的。

根据标准12.6.3/p1通过继承的构造函数[class.inctor.init]初始化(Emphasis Mine):

当调用类型B的构造函数来初始化不同类型的D(即继承构造函数时(7.3.3)),初始化继续进行,就好像默认默认一样构造函数用于初始化D对象和每个基类继承构造函数的子对象,B除外子对象通过调用继承的构造函数完整的初始化被认为是单个函数调用;特别是,继承的初始化构造函数的参数在初始化任何CCD_ 9对象的一部分。

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

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

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

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

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

也就是说,Derived类中的using声明隐式地定义了构造函数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) {}
};

毕竟CCD_ 15和CCD_ 16是不同的类,即使第一个继承了第二个。