【问题标题】:Inheriting copy and move constructors of base class using "using" keyword使用“using”关键字继承基类的复制和移动构造函数
【发布时间】:2018-08-09 05:54:00
【问题描述】:

我想使用using关键字继承基类的复制构造函数:

#include <iostream>

struct A
{
    A() = default;

    A(const A  &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }
    A(      A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }

    A& operator=(const A  &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
    A& operator=(      A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
};

struct B : A
{
    using A::A;
    using A::operator=;

    B& operator=(const B  &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
    B& operator=(      B &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
};

int main()
{
    A a;
    B b;
    b = a; // OK
    B b1(          a ); // compile error
    B b2(std::move(a)); // compile error
    return 0;
}

使用using 关键字继承赋值运算符可以正常工作,但继承复制和移动构造函数会导致编译错误:继承的构造函数不适合从相同或派生类型的表达式进行初始化 .

http://coliru.stacked-crooked.com/a/fe84b429c391c894:

main.cpp:16:14: note:   an inherited constructor is not a candidate for initialization from an expression of the same or derived type
main.cpp:8:5: note: candidate: A::A(A&&)
     A(      A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }
     ^
main.cpp:16:14: note:   inherited here
     using A::A;

为什么我可以继承赋值运算符但不能继承复制构造函数?有什么区别?如果我也不能继承赋值运算符,我可以理解。但是相反地继承赋值运算符被认为是可以的。这对我来说有点奇怪。

故事

我想要的类似于this 问题中提出的问题:我只想向现有类添加新方法而不修改它(它是来自另一个库的类)。

http://coliru.stacked-crooked.com/a/149a6194717cd465:

#include <iostream>

struct A // not my class
{
};

struct B : A
{
    using A::A;
    using A::operator=;

    void foo() { std::cerr << "fuu" << std::endl; }
};

A NotMyFunc()
{
    return {};
}

int main()
{
    B b(NotMyFunc());
    b.foo();
    return 0;
}

但我不想重新实现复制和移动构造函数。

【问题讨论】:

  • Pretty_Function 不是标准的。
  • @JiveDadson,但它仍然很漂亮。
  • 不在我的编译器上。它不见了。
  • 因为标准是这样说的。 “如果从基类引入派生类的构造函数或赋值运算符具有派生类(15.8)的复制/移动构造函数或赋值运算符的签名,则使用声明本身不会抑制隐式声明派生类成员;来自基类的成员被派生类的隐式声明的复制/移动构造函数或赋值运算符隐藏或覆盖”。
  • 对不起,这是一个错误的理由!它不起作用,因为“具有 派生 类的复制/移动构造函数或赋值运算符的签名”。它适用于A::A(const B&amp;),但不适用于这种情况。正确的理由是here。请注意,它仅适用于构造函数,不适用于赋值运算符。

标签: c++ inheritance copy-constructor move-constructor


【解决方案1】:

您需要一个以 A 作为参数的 B 构造函数。然后你需要明确默认构造函数。

struct B : A
{
    using A::A;
    using A::operator=;

    B() = default;
    B(const A& a) : A(a) {}
    B(A &&a): A(std::move(a)) {}
};

【讨论】:

  • 我不需要显式添加默认构造函数。没有它也可以工作 (coliru.stacked-crooked.com/a/bf8d566e8575fbe6)。将构造函数从 A 添加到 B 是我试图避免的。
  • 您确实需要在添加单行 B(const A&amp; a) : A(a) {} 后明确默认构造函数,这是必需的。要么接受,要么离开。
  • 我不知道。我刚刚向您展示了一个示例,它可以在没有B() = default; 的情况下正常编译。但也许它是 gcc 扩展。
  • 无论如何,你都有答案。祝你好运。
猜你喜欢
  • 2014-08-29
  • 1970-01-01
  • 2014-03-08
  • 2013-02-27
  • 1970-01-01
  • 1970-01-01
  • 2017-11-17
  • 1970-01-01
相关资源
最近更新 更多