我知道一旦创建了一个对象,我就不会乱用V-Table(以一种有点理智的方式)。这意味着我必须复制一个对象来改变它的类型。这对c ++ 11的std :: move和朋友来说也适用吗?
class Base {
public:
virtual int type() = 0;
// more data members I want to avoid to copy
};
class D1 : public Base {
public:
int type() {
return 1;
}
};
class D2 : public D1 {
public:
int type() {
return 2;
}
};
int main()
{
// creating the actual object, type is D1
D1* obj = new D1();
// this is what does not work, I want to "change" the object to D2
D2* obj2 = &std::move<D2>(*obj);
// cast it to obj2 base class
Base* baseObj = static_cast<D1*>(obj2);
// now I want a "2" here
int t = baseObj->type();
printf ("%d\n", t);
}
我不太清楚移动语义......但是有什么东西可以将D1对象改为D2(反之亦然)类型安全吗? (这两个类在内存布局上几乎相同)
答案 0 :(得分:4)
虽然您无法更改现有对象的类型,但您可以轻松更改指针成员的动态类型并获得所需的效果。这称为策略设计模式。
E.g:
#include <memory>
#include <iostream>
class Host
{
struct Strategy
{
virtual ~Strategy() = default;
virtual int type() const = 0;
};
struct StrategyA : Strategy { int type() const override { return 1; } };
struct StrategyB : Strategy { int type() const override { return 2; } };
std::unique_ptr<Strategy> strategy_;
public:
Host()
: strategy_(new StrategyA)
{}
int type() const { return strategy_->type(); }
void change_strategy(int type) {
switch(type) {
case 1: strategy_.reset(new StrategyA); break;
case 2: strategy_.reset(new StrategyB); break;
default: std::abort();
}
}
};
int main() {
Host host;
std::cout << host.type() << '\n';
host.change_strategy(2);
std::cout << host.type() << '\n';
}
答案 1 :(得分:1)
在我看来,你并不熟悉std::move
实际上做的事情。
正如其他人所说,std::move
实际上并没有移动任何东西。它从xvalue
(基本上是命名变量)获得lvalue
(具有名称,但可以将其资源重用或转移到另一个对象的变量)的引用,因此,std::move
只不过是一个演员。它不会创建任何新对象。详细了解here和here。
仍然关于移动语义主题,
std::move
非常有用,因此您可以强制rvalue-aware方法接收和重用您绝对知道可以移动其资源的变量中的资源。
为了更深入地了解这一点,我建议您阅读What are move semantics?。例如,它的一个用途是从临时创建一个对象(例如,在函数内创建然后返回的对象):
#include <vector>
#include <iostream>
class A {
public:
// A very large resource
std::vector<int> resource;
// Constructs our very large resource
A(): resource(1024, 0) { std::cout << "Default construct" << std::endl; }
// Move (reuses) a very large resource from an instance
A(A && other) : resource(std::move(other.resource)) {
std::cout << "Move construct" << std::endl;
}
};
现在,A
移动构造函数仅在other
对象为rvalue
(或xvalue
)时调用,例如:
A foo(A a) { return a; }
int main() {
A a = foo(A());
return 0
}
在这种情况下,在调用foo()
之前,会创建一个临时A()
并作为参数传入。 foo()
会返回它,但由于它是临时的,因此它适合rvalue
并在构造A
时传递给A a = foo(A())
的移动构造函数。
在A()
的移动构造函数中,std::move(other.resource)
用于构造另一个resource
以调用std::vector
的移动构造函数,以便它可以尝试使用它可以使用的任何内容来自other.resource
,而不是从头开始创建所有内容(然后再复制)。
但如前所述,std::move
本身并没有移动任何内容,但它可以传达 intent 来移动,帮助编译器做正确的事(和其他程序员阅读它并更快地理解你的意思。)
所以,要直接回答你的问题,不,除了构建一个新对象之外,没有任何东西可以让你将一个对象转换成另一个对象。如果您确定要销毁obj
(顺便说一下,您没有这样做),则可以实现D2
的构造函数,该构造函数接受rvalue
D1
}}:
class D2 {
public:
D2(D1 && d1) : resource(std::move(d1.resource)) { d1.resource = nullptr; }
}
int main() {
D1 * obj = new D1();
D2 * obj2 = new D2(std::move(*obj));
delete obj;
}
但是,在执行此操作时还需要考虑其他事项,例如移动对象的析构函数和其他详细信息。我建议您阅读有关该主题的更多信息,也可以使用不同的方法来实现您正在做的事情,例如另一个答案中提到的策略模式。