1

I have many classes which represent different kinds of animals. The idea is that if two animals of the same species meet then new animal of this species should be created - it means that I want to create a new intance of the specific class in this situation. If bears will meet i want to create new instance of bear, when bats meet then new instance of bat.

How can I achieve this goal without duplicating code? I want to avoid making individual if condition for each class (animal). I'm looking for the solution where new instance of a class will be created automatically based on the class of the existing instance.

SigGP
  • 716
  • 1
  • 11
  • 24
  • 2
    Looks like you are looking for [this](http://stackoverflow.com/questions/5148706/copying-a-polymorphic-object-in-c) – NathanOliver Apr 21 '17 at 16:33
  • The scenario you describe sounds a lot like double dispatch. I suggest you lookup for that. – Emerald Weapon Apr 21 '17 at 16:35
  • A lot depends on what exactly you mean when you say "meet". Do you have two instances of `Animal` and want to create a new instance of `Bear` if both `Animal`s are `Bear`s? If so, what should happen if one of them is not a `Bear`? – Christian Hackl Apr 21 '17 at 17:36

2 Answers2

2

Since you know that both parent object must have the same type, you don't quite need the usual double-dispatching solutions -- these are made to deal with all possible combinations.

Let's just use a slightly modified variant of the Clone pattern. Animal, the base class, gets a pure virtual cloning function:

struct Animal {
    virtual std::unique_ptr<Animal> mateWith(Animal const &other) const = 0;
};

Then, every subclass implements this method, checking through RTTI that the other Animal is actually the right type:

struct Bear : Animal {
    std::unique_ptr<Animal> mateWith(Animal const &other) const override {
        auto &otherBear = dynamic_cast<Bear const &>(other);
        return std::make_unique<Bear>(*this, otherBear);
    }
};

This will throw std::bad_cast if the other animal is not a bear. You can also replace this with some other error handling:

struct Bear : Animal {
    std::unique_ptr<Animal> mateWith(Animal const &other) const override {
        auto *otherBear = dynamic_cast<Bear const *>(&other);
        if(!otherBear) {
            // This is not a bear!
        }

        return std::make_unique<Bear>(*this, *otherBear);
    }
};
Quentin
  • 62,093
  • 7
  • 131
  • 191
1

You can compare the types generically using the following:

#include <typeinfo>

if ( typeid(YourClass1) == typeid(YourClass2) )
// do something

To create a new instance, add a pure virtual clone to your Base class, then implement it in every animal.

You can also add a name field to the Base class, and compare with that.

class Animal{
public:
    virtual shared_ptr<Animal> clone() = 0;
    virtual const string &  getname() = 0;
};
class Bear: public Animal{
public:
    virtual shared_ptr<Animal> clone()
    {
        return shared_ptr<Animal>(new Bear());
    }
    virtual const string & getname()
    {
        return "bear";
    }
};


int main(int argc, const char * argv[])
{
    Bear b1;
    Bear b2;
    shared_ptr<Animal> b3;
    if ( b2.getname() == b2.getname() )
        b3 = ( b1.clone() );
  ...
}
didiz
  • 1,069
  • 13
  • 26
  • But this solution requires to create new methods for each class. I am looking for solution where class of existing instance will be detected and then new instance of the same class will be created automatically. – SigGP Apr 21 '17 at 16:56
  • in that case you can take the name using typeid(YourClass1).name, then use the string returned to get a new class instance from a Factory class, as mentioned above. Fully dynamic creation is not allowed as the compiler must know the type at compiler time. Good Luck! – didiz Apr 21 '17 at 17:17