I want a derived class to be able to copy from another class if it has the same type, if not just do nothing.
Example in semi-pseudocode:
class Animal
{
public:
virtual void CopyFrom(Animal* animal) = 0;
// TODO: virtual destructor
};
class Dog : Animal
{
public:
Dog() {}
void CopyFrom(Animal* animal) override {
if (animal is Dog) {
likes_to_bark = ((Dog)animal).likes_to_bark;
}
}
private:
bool likes_to_bark;
}
I know this can be achieved a dynamic cast, but that is considered code smell. I was looking into the visitor pattern and double dispatch, but I could not find a way to do this. Any ideas?
CodePudding user response:
if (animal is Dog)
C has a solution for you: RTTI. Unless disabled, it allows dynamic_cast
to cast a down-pointer (to parent type) to an up-pointer (to derived type) and returns a null pointer if the cast isn't possible.
if (dynamic_cast<Dog*>(animal)) {
// this bloc is only executed if animal is indeed a Dog
}
Additionally, you could tweak and rename your function copyFrom
to operator=
, allowing nice user syntax:
Dog& operator=(Dog const& other) = default // or define it if it has specificities
Dog& operator=(Animal const& animal)
{
Dog const* other = dynamic_cast<Dog const*>(&animal)
if (other) {
*this = *other;
}
return *this;
}
int main()
{
Animal spider;
Dog pluto, laika;
Animal& animal = pluto;
laika = spider; // does nothing
laika = animal; // copies pluto to laika
}
I know this can be achieved a dynamic cast, but that is considered code smell.
A code-smell is what it is: a smell. I'd rather see a simple code using dynamic_cast
in a proper manner that something trying to hide it uses casting under the hood in a convoluted way.
The tool is available, it can be used. Just avoid abusing it.
CodePudding user response:
rtti is of course necessary but you can achieve this readily in the base:
class Animal
{
public:
virtual void CopyFrom(Animal* animal){
if(typeid(this) == typeid(animal){
*this = *animal;
}
}
};