I have an object which I want to 'transform' into another object. For this I am using a placement new
on the first object which creates a new object of the other type on top of its own address.
Consider the following code:
#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();
}
};
You can see that when a Dog
is called with transform
it creates a new Cat
on top of the given address.
Next, I will call the Dog::transform
with its own address:
#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;
}
The results of this is:
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
My questions are:
- Is this operation considered safe, or does it leave the object in unstable state?
- After the transform I call
dog.voice()
. It correctly prints the nameCAT
(it is now a cat), but still writesWOOF I am a
, even though I would have thought that it should call theCat
'svoice
method? (You can see is that I call the same method but by the address ((&dog)->voice()
), everything is working properly.