从派生副本构造函数调用base的move构造函数

时间:2019-12-08 14:06:14

标签: c++ inheritance constructor

我是SO的新手,所以让我知道是否需要更改任何内容。我竭尽全力提供示例代码。我知道已经问过许多类似的问题,但是我找不到与我的特定问题匹配的问题。

此外,我知道我在做的事情不是用“真实”代码做的事情,我只是想更好地理解r / l / p / x..values。 / p>

我有一个基类和一个派生类,它们都有默认,复制和移动构造函数。现在,我想让派生类的副本构造函数调用基类的move构造函数。

class Base
{
public:
    Base(){ std::cout << "default base constructor called.\n"; }

    Base(Base const &other) { std::cout << "copy base constructor called.\n"; }

    Base(Base &&tmp) { std::cout << "move base constructor called.\n"; }
};

与派生类基本相同:

class Derived : public Base
{
public:
    Derived(){ std::cout << "default derived constructor called.\n";}

    Derived(Derived const &other)
    :
        Base(std::move(other))   // here I want to call Base(Base &&tmp)
    {
        std::cout << "copy derived constructor called.\n";
    }

    Derived(Derived &&tmp)
    :
        Base(std::move(tmp))     // correctly calls Base(Base &&tmp)!
    {
        std::cout << "move derived constructor called.\n";
    }
};

所以在我的主函数中,我现在要调用复制构造函数,然后再调用基类的move构造函数。

int main()
{
    Derived der{};
    Derived der_copy{ der };
    Derived der_move{ std::move(der) };
}

我得到的输出是这样:

default base constructor called.
default derived constructor called.
copy base constructor called.         <-- why not move?
copy derived constructor called.
move base constructor called.
move derived constructor called.

我期望以下几点:

default base constructor called.
default derived constructor called.
move base constructor called.
copy derived constructor called.
move base constructor called.
move derived constructor called.

因此,当我在派生的移动构造函数中使用std::move(tmp)时(在Base &&tmp上),将调用基本move构造函数,但是当我在派生的复制构造函数中使用std::move(other)时(因此在Base const &other上调用了基本副本构造函数?

TBH,这似乎太奇怪了,以至于我怕自己在代码中犯了一个错误,我多次检查了所有内容,但似乎无法在上述情况下调用move base构造函数... < / p>

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

在复制构造函数中

Derived(const Derived& other)

std::move(other)将导致类型为const Derived&&的xvalue表达式。

这是一个合法但有些奇怪的类型:std::move(other)是一个临时对象,但是您不能从它移开,因为它是常量。此类引用具有limited number of use cases。有关一个特定示例,请参见std::as_conststd::ref的声明。

const Derived&&无法绑定到Base&&,这就是为什么在之间的重载解析期间

Base(const Base&)
Base(Base&&)

前者由编译器选择。

冒着获得不确定行为的风险,您可以放弃constness并编写

Derived(const Derived& other) : Base(std::move(const_cast<Derived&>(other))) {}

调用Base的move构造函数。但是不要在真实代码中这样做。

答案 1 :(得分:1)

您需要像这样更改您的基类:

Base(const Base &&tmp) { std::cout << "move base constructor called.\n"; }