【发布时间】:2019-09-06 17:40:30
【问题描述】:
我有一个对象,我想将其“转换”为另一个对象。为此,我在第一个对象上使用了placement new,它在自己的地址之上创建了另一个类型的新对象。
考虑以下代码:
#include <string>
#include <iostream>
class Animal {
public:
virtual void voice() = 0;
virtual void transform(void *animal) = 0;
virtual ~Animal() = default;;
};
class Cat : public Animal {
public:
std::string name = "CAT";
void voice() override {
std::cout << "MEOW I am a " << name << std::endl;
}
void transform(void *animal) override {
}
};
class Dog : public Animal {
public:
std::string name = "DOG";
void voice() override {
std::cout << "WOOF I am a " << name << std::endl;
}
void transform(void *animal) override {
new(animal) Cat();
}
};
您可以看到,当使用transform 调用Dog 时,它会在给定地址之上创建一个新的Cat。
接下来,我会用自己的地址调用Dog::transform:
#include <iostream>
#include "Animals.h"
int main() {
Cat cat{};
Dog dog{};
std::cout << "Cat says: ";
cat.voice() ;
std::cout << "Dog says: ";
dog.voice();
dog.transform(&dog);
std::cout << "Dog says: ";
dog.voice();
std::cout << "Dog address says: ";
(&dog)->voice();
return 0;
}
这样的结果是:
Cat says: MEOW I am a CAT
Dog says: WOOF I am a DOG
Dog says: WOOF I am a CAT
Dog address says: MEOW I am a CAT
我的问题是:
- 此操作是否被认为是安全的,还是会使对象处于不稳定状态?
- 转换后我调用
dog.voice()。它正确地打印了名称CAT(它现在是一只猫),但仍然写了WOOF I am a,即使我认为它应该调用Cat的voice方法? (您可以看到,我调用了相同的方法,但通过地址 ((&dog)->voice()),一切正常。
【问题讨论】:
-
我无法引用标准中的哪个地方说这是不允许的,但我可以说我在系统的两条底线中都得到了“WOOF I am a CAT”,这是一个很好的指标,表明这种行为是不可移植的。
-
如果您需要这种行为,我将其描述为“对象似乎会改变它的类”,请考虑使用四态模式:en.wikipedia.org/wiki/State_pattern
标签: c++ placement-new