Monday, May 6, 2013

The "same" return type

Look at this piece of C++ code:
#include <string>
#include <iostream>

using namespace std;

class Animal {
    public:

    string color;

    virtual Animal * clone() {
        Animal * new_animal = new Animal(*this);
        return new_animal;
    }
};

class Dog : public Animal {
    public:

    int fangs;

    Dog() : fangs(4) {}

    Dog * clone() {
        Dog * new_dog = new Dog(*this);
        return new_dog;
    }
};

class Cat : public Animal {
    public:

    int tail_length;

    Cat() : tail_length(10) {}

    Cat * clone() {
        Cat * new_cat = new Cat(*this);
        return new_cat;
    }
};

class Shop {
    public:

    string animals_color;

    Animal * new_like(Animal * a) {
        Animal * new_animal = a->clone();
        new_animal->color = this->animals_color;
        return new_animal;
    }
};

int main(void) {
    Cat c;
    c.color = "white";

    Shop s;
    s.animals_color = "black";

    Cat * new_cat = dynamic_cast<Cat*>(s.new_like(&c));

    cout << new_cat->color;
}

As you can see, dynamic_cast is used here ("static" is also suitable though), because we know that the return type of new_like() is always the same as its argument (as it uses clone() inside).

Of course this is ugly. How do you improve this without significant changes?

1 comment:

  1. The simplest solution is to use template method of shop

    class Shop {
    public:

    string animals_color;
    template
    T * new_like(T * a) {
    T * new_animal = a->clone();
    new_animal->color = this->animals_color;
    return new_animal;
    }
    };

    int main(void) {
    Cat c;
    c.color = "white";

    Shop s;
    s.animals_color = "black";

    Cat * new_cat = s.new_like(&c);

    cout << new_cat->color;
    }

    ReplyDelete