【问题标题】:C++, inherited copy ctors does not work?C ++,继承的复制ctors不起作用?
【发布时间】:2016-10-01 20:12:07
【问题描述】:

考虑以下代码:

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);

但是all compilers 拒绝了这些错误消息

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

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

更新 下面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)

【问题讨论】:

  • 因为特殊的成员函数没有被继承?那是没有意义的。你最终得到的不是“复制构造函数”。

标签: c++ c++11


【解决方案1】:

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

关于 cppreference 的评论具有误导性(1)。标准中的相同评论说:

D1B1 的继承构造函数的候选集

(强调我的)。

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

详情请参阅 C++14 12.9 [class.inhctor]。


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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      当调用B 类型的构造函数来初始化一个对象时 不同类型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) {}
        ...
      };
      

      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) {}
      };
      

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

      【讨论】:

      • 你能解释一下为什么我不能继承 ctors 吗?另请参阅更新。
      猜你喜欢
      • 1970-01-01
      • 2013-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多