Home > OS >  Copy internal details from other object with abstract data type
Copy internal details from other object with abstract data type

Time:10-25

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;
     }
  }
};
  • Related