宣告RValue方法(例如void operation()&&;)虚拟C ++ 1x

时间:2016-02-06 21:56:38

标签: c++ c++11 c++14 rvalue-reference rvalue

这可能有些奇特: (我正在努力更新新的c ++标准) 是否有任何理由在类中声明RValue方法 例如void operation() &&; virtual?我无法想象,因为操作 仅适用于临时对象,例如Base().operation()Derived().operation()createObject().operation()之类的内容。 表达式createObject()必须返回一个对象和 不是引用也不是指针,因为它们必须两者兼而有之 引用左值对象。 由于类型切片,总是调用Base::operation()。 如果您有一个Derived()的对象,则会调用Derived::operation(), 然而,它在Base中是虚拟的。 那么,我是否有理由认识到,我是否已经监督过? 感谢您的灵感!

哦,是的,我忘记了,RValue有演员阵容:前进和前进! 谢谢你!

我的发现是: 1.调用RValue参考资格 操作(rqOp()&&),我们总是要使用std :: forward< ..> 例外:Derived()。rqOp(); 2.声明RValue引用合格是有意义的 操作虚拟

由于以下原因: 给定Base和Derived类 使用重载的引用限定操作rqOp() 和一个名为op()的非参考资格:

class Base{
public:
    virtual ~Base() = default;
    virtual
    void rqOp() &&;
    virtual void rqOp() &;
    virtual void op();

};
class Derived : public Base{
public:
    //virtual
    void rqOp() &&; //override;
    virtual void rqOp() & override;
    virtual void op() override;
};

和一个重载函数:

void callOperationF(Base& b){
    cout << "callOperationF(Base& b)" << endl;

    cout << "b.rqOp();" << endl;
    b.rqOp();
}
void callOperationF(Base&& b){
    cout << "callOperationF(Base&& b)" << endl;

    cout << "b.rqOp();" << endl;
    b.rqOp();

    cout << "std::forward<Base&&>(b).rqOp();" << endl;
    std::forward<Base&&>(b).rqOp();

    cout << "std::forward<Base&&>(b).op();" << endl;
    std::forward<Base&&>(b).op();
}

以及对该重载的一些调用:

cout << "== Derived d;" << endl;
Derived d;

cout << endl;
cout << "== callOperationF(d);" << endl;
callOperationF(d);

cout << endl;
cout << "== callOperationF(Derived());" << endl;
callOperationF(Derived());

产生输出:

== Derived d;

== callOperationF(d);
callOperationF(Base& b)
b.rqOp();
Derived::rqOp() &

== callOperationF(Derived());
callOperationF(Base&& b)
b.rqOp();
Derived::rqOp() & ===> 1
std::forward<Base&&>(b).rqOp();
Derived::rqOp() && ===> 2
std::forward<Base&&>(b).op();
Derived::op()

我们可以看到,要调用RValue参考资格 操作(rqOp()&amp;&amp;),我们需要使用forward&lt; ..&gt; 在===&gt; 1不是RValue合格的! 因为b是LValue表达式。 在===&gt; 2使用std :: forward&lt; ..&gt;正确的方法 被称为和 非引用限定操作(op())是 正确使用std :: forward&lt; ...&gt;调用。 如果我们改变界面和 重载op()引用限定,它仍然会 调用正确的方法,RValue参考文献中的一个。

使用模板化功能,如下所示:

template<class T>
void callOperationT(T&& t){
    cout << "callOperationT(T&& t)" << endl;
    cout << "t.rqOp()" << endl;
    t.rqOp();
    cout << "std::forward<T>(t).rqOp();" << endl;
    std::forward<T>(t).rqOp();
    cout << "std::forward<T>(t).op();" << endl;
    std::forward<T>(t).op();
}

以及对此函数的一些调用,使用上面的Derived d:

cout << endl;
cout << "== callOperationT(d);" << endl;
callOperationT(d);

cout << endl;
cout << "== Base& bRef = d;" << endl;
Base& bRef = d;
cout << "== callOperationT(move(bRef));" << endl;
callOperationT(move(bRef));

cout << endl;
cout << "== callOperationT(Derived());" << endl;
callOperationT(Derived());

产生输出:

== callOperationT(d);
callOperationT(T&& t)
t.rqOp()
Derived::rqOp() &
std::forward<T>(t).rqOp();
Derived::rqOp() &
std::forward<T>(t).op();
Derived::op()

== Base& bRef = d;
== callOperationT(move(bRef));
callOperationT(T&& t)
t.rqOp()
Derived::rqOp() &
std::forward<T>(t).rqOp();
Derived::rqOp() && ===> 3
std::forward<T>(t).op();
Derived::op()

== callOperationT(Derived());
callOperationT(T&& t)
t.rqOp()
Derived::rqOp() &
std::forward<T>(t).rqOp();
Derived::rqOp() &&
std::forward<T>(t).op();
Derived::op()

具有相同的发现:调用RValue引用合格 操作(rqOp()&amp;&amp;),我们需要使用forward&lt; ..&gt; 在===&gt; 3 Base :: rqOp()&amp;&amp;将被调用,如果rqOp 不是虚拟的。

谢谢!

2 个答案:

答案 0 :(得分:1)

  

我无法想象,因为该操作仅适用于临时对象

不一定。 rvalue ref-qualified函数要求将对象绑定到右值引用。也就是说,您可以使用一个函数返回对Base的右值引用,但动态类型为Derived

struct Base {
    virtual void f() && { std::cout << "Base\n"; };
    virtual ~Base() = default;
};

struct Derived : Base
{
    void f() && override { std::cout << "Derived\n"; }
} child;

Base&& Get() {
    return std::move(child);
}

int main() {
    Get().f(); // Derived
}

答案 1 :(得分:1)

我用过它的地方是在派生类实现的基类中创建一个unique_ptr复制或移动函数:

class Base {
    ... whatever else
    virtual std::unique_ptr<Base> mkuniq() && = 0;
    virtual std::unique_ptr<Base> mkuniq() const & = 0;


class Derived : public Base
    ...
    std::unique_ptr<Base> mkuniq() && { return std::make_unique<Derived>(std::move(*this)); }
    std::unique_ptr<Base> mkuniq() const & { return std::make_unique<Derived>(*this); }

这允许我编写其他函数,将Base &&作为一个句子,如果需要,可以在某个时刻转入unique_ptr<Base>。然后可以使用未命名的Derived临时调用所述函数。当然,需要大量调用std::move才能将命名的右值引用转回到未命名的右值引用中,但在处理右值引用时这是预期的。