这可能有些奇特:
(我正在努力更新新的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 不是虚拟的。
谢谢!
答案 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
才能将命名的右值引用转回到未命名的右值引用中,但在处理右值引用时这是预期的。