Проверка типа производного класса - PullRequest
1 голос
/ 16 июня 2011

Это пример проблемы, с которой я столкнулся при разработке интерфейса.

У меня есть класс Animal, и я получил от него Cat, Dog и Lion.Теперь у меня есть функция feedFood, которая принимает базовый класс Animal в качестве параметра.Основываясь на типе животного, я должен кормить животных различными видами пищи.

Так как мне проверить тип животного в функции feedFood.

Есть 3 метода, о которых я могу подумать

  • Добавление перечисления AnimalType в базовый класс, для которого в производном классе задан правильный тип.
  • Добавьте виртуальную функцию в базовый класс, чтобы вернуть строку с типом животного.В производном классе верните подходящую строку для имени животного.
  • Используйте typeid или dynamic_cast для проверки типа производного класса в функции feedFood.

Что является лучшимметод или есть другой лучший подход для этого?

Ответы [ 4 ]

6 голосов
/ 16 июня 2011

Вы в настоящее время говорите это:

void feedFood(Animal &);

Cat myCat;
Dog myDog;

feedFood(myCat);
feedFood(myDog);

// Problem: How does feedFood() know what's going on?

Чтобы использовать полиморфизм, сделайте функцию кормления виртуальным членом Animal:

struct Animal
{
  virtual void feedFood() = 0; // pure virtual or default behaviour, up to you
  virtual ~Animal() { }        // always provide virtual destructor!
  /* ... */
};

struct Cat : public Animal
{
  void feedFood() { /* Cat implementation */ }
  /* ... */
};

// Usage:

// via reference
void feed(Animal & a) { a.feedFood(); }

// via pointer
Animal * b = new Bat;
b->feedFood();
1 голос
/ 19 июня 2011

Хорошо, немного сложно, но разрешается во время компиляции:

template <class _Derived>
class Animal
{};

class Dog: public Animal<Dog>
{
public:
    void Feed()
    {
        cout<<"Feeding Dog...";         
    }
};

class Cat: public Animal<Cat>
{
public:
    void Feed() { /* Feed Cat*/ }  
};

И реализовать ОДНУ шаблонную функцию:

template<class _AnimalType>
void FeedAnimal(_AnimalType& animal)
{
    animal.Feed();
}

Создать экземпляр любого класса и вызвать FeedAnimal :

Dog dog;
Cat cat;
FeedAnimal(dog);
FeedAnimal(cat);

Если Feed не реализован производный-класс , вы не сможете получить ошибку, пока не вызовете функцию шаблона Feed. Поэтому, если Lion реализован так:

class Lion : public Animal<Lion>
{};

Вы не получите никакой ошибки, которой нет в Feed. Как только вы сделаете вызов FeedAnimal с Lion, вы получите сообщение об ошибке, что у Lion отсутствует метод Feed.

Это один из способов убедиться, что производный класс реализует Feed:

template <class _Derived>
class Animal
{
    void (_Derived::*pDummy)();
public:
    Animal()
    {
        pDummy = &_Derived::Feed;       
    }
};

Грязно, но работает!

1 голос
/ 16 июня 2011

Попробуйте это:

class Animal{};
class Dog: public Animal{};
class Cat: public Animal{};
class Lion: public Animal{};

void FeedFood(Dog& d)
{
    cout << "Feeding the dog.\n";
    return;
}

void FeedFood(Cat& c)
{
    cout << "Feeding the cat.\n";
    return;
}

void FeedFood(Lion& l)
{
    cout << "Feeding the lion.\n";
}

void FeedFood(Animal& a)
{
    cout << "Feeding an unknown animal.\n";
    return;
}

С помощью вышеуказанных функций компилятор позаботится о кормлении животных.

Иногда функциональность лучше размещать вне класса.

0 голосов
/ 16 июня 2011

Не животное получает пищу, а съедает ее. Поэтому добавьте виртуальный метод «есть» вместе с некоторым FoodProvider, на котором может питаться животное.

Обновление

Так что вместо

void feed (const Food & food);

использование

virtual void eatFrom (FoodProvider * provider);

Таким образом, вы также можете использовать различные ресурсы питания у своего поставщика.

...