加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 多拷贝构造函数继承中的令人惊讶的行为

发布时间:2020-12-16 09:21:11 所属栏目:百科 来源:网络整理
导读:从C 11开始,可以有两个复制构造器,一个采用类型为T的参数,另一个采用类型为const T的参数. 我有一种情况,即(似乎)添加第二个复制构造函数会导致在构造函数在派生类中继承时不会调用任何一个.当两者都存在时,复制构造函数被模板化构造函数覆盖. 这是一个MWE:
从C 11开始,可以有两个复制构造器,一个采用类型为T&的参数,另一个采用类型为const T&的参数.

我有一种情况,即(似乎)添加第二个复制构造函数会导致在构造函数在派生类中继承时不会调用任何一个.当两者都存在时,复制构造函数被模板化构造函数覆盖.

这是一个MWE:

struct A {
  template <typename... Args>
  A (Args&&... args)
  { std::cout << "non-default ctor calledn"; }

  A (A&) { std::cout << "copy ctor from non-const refn"; }
};

struct C :public A { using A::A; };

int main() {
  C c1;
  C c2(c1);
}

运行此代码,我们看到输出

non-default ctor called
copy ctor from non-const ref

这是预期的.

但是,如下所示为结构A添加一个额外的构造函数:

A (const A&) { }

以某种方式导致其他复制构造函数不被调用,因此输出变为

non-default ctor called
non-default ctor called

在我的用例中,我想将所有构造函数从基类继承到派生类,包括复制构造函数和其他任何东西.但似乎不知何故,当两个拷贝构造函数都存在时,它们不会被继承.这里发生了什么?

解决方法

从 https://en.cppreference.com/w/cpp/language/using_declaration起

If one of the inherited constructors of Base happens to have the signature that matches a copy/move constructor of the Derived,it does not prevent implicit generation of Derived copy/move constructor (which then hides the inherited version,similar to using operator=).

所以

struct C :public A { using A::A; };

struct C :public A
{
    using A::A;
    C(const C&) = default;
    C(C&&) = default;
};

其中C(const C&)=默认值;类似于

C(const C& c) : A(static_cast<const A&>(c)) {}

所以

struct A {
  template <typename... Args>
  A (Args&&... args)
  { std::cout << "non-default ctor calledn"; }

  A (A&) { std::cout << "copy ctor from non-const refn"; }
};

选择模板构造函数,但是

struct A {
  template <typename... Args>
  A (Args&&... args)
  { std::cout << "non-default ctor calledn"; }

  A (const A&) { std::cout << "copy ctor from const refn"; }
  A (A&) { std::cout << "copy ctor from non-const refn"; }
};

选择A(const A&).

您可以注意到,还有一个缺陷:

The semantics of inheriting constructors were retroactively changed by a defect report against C++11. Previously,an inheriting constructor declaration caused a set of synthesized constructor declarations to be injected into the derived class,which caused redundant argument copies/moves,had problematic interactions with some forms of SFINAE,and in some cases can be unimplementable on major ABIs. Older compilers may still implement the previous semantics.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html

有了这个缺点,你的C级就是

struct C :public A
{
    using A::A;

    template <typename ...Ts>
    C(Ts&&... ts) : A(std::forward<Ts>(ts)...) {} // Inherited.

    C(const C&) = default;
    C(C&&) = default;
};

所以你调用C(C& c):A(c){}(在模板替换之后).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读