Как обращаться с одним подклассом есть метод, в то время как другой подкласс не имеет его?

0

У меня вопрос о интерфейсе, скажем:

class IAnimal
{ ...
Public:
    virtual void makeSound() = 0;
};

class Cat : public IAnimal
{  ...
    void makeSound() { std::cout << "purr" << std::endl; }
};
class Dog : public IAnimal
{  ...
    void makeSound() { std::cout << "bark" << std::endl; }
};
class AnimalFactory
{
    std::shared_ptr<IAnimal> createAnimal(animalType type)
    {  
        std::shared_ptr<IAnimal> animal;
        switch(type)
        { case animal_type::cat: animal = std::shared_ptr<Cat>(); break; 
          case animal_type::dog: animal = std::shared_ptr<Dog>(); break; 
        … }
        return animal;
    }
};

class App
{ ...
    std::shared_ptr<IAnimal> _animal;
    AnimalFactory::animal_type type;
    void haveCat()
    { ...
        type = AnimalFactory::animal_type::cat;
        _animal = AnimalFactory.createAnimal(type);
        _animal->makeSound();
        ...
    } 
};

теперь мне нужна эта кошка, чтобы поймать мышь void catchMouse() {std :: cout << "поймать мышей"; } }

void haveCat()
{ ...
  type = AnimalFactory::animal_type::cat;
  _animal = AnimalFactory.createAnimal(type);
  _animal->makeSound();
  // catchMouse();
  ...
}

Существует несколько возможных решений, но они не выглядят хорошо.

  1. добавьте метод в IAnimal, затем после создания cat с помощью AnimalFactory я могу вызвать метод catchMouse() из IAnimal. но catchMouse не для всех животных, собака не ловит мышь. Добавление метода в IAnimal загрязняет интерфейс, код запаха.
  2. добавьте общедоступный метод catchMouse() в Cat и добавьте _animal в метод Cat в hasCat().

    {
    _cat = std::dynamic_pointer_cast<Cat>(AnimalFactory.createAnimal(type));
    _cat->makeSound();
    _cat->catchMouse();
    }
    

    но есть динамичный бросок, а не хороший, не так ли?

  3. пусть Cat реализует интерфейс IAnimal и еще один интерфейс о мыши, но AnimalFactory возвращает только std :: shared_ptr, и мы не можем вызвать catchMouse в IAnimal.

То, что я говорю здесь, - это публичный метод в одном подклассе, но другого подкласса нет, как его проектировать, если мы используем фабрику. Пожалуйста, не отвечайте, позвольте собаке поймать кролика, затем добавьте метод catch() в IAnimal, поэтому кошка может поймать мышку, собака может поймать кролика.

Какое хорошее решение для этого вопроса? Благодарю.

  • 0
    Зачем быть таким конкретным? Что-то вроде find_food , collect_food , consume_food должно быть достаточно.
  • 0
    makeSound выглядит как виртуальная функция.
Показать ещё 4 комментария
Теги:
inheritance
interface
factory
subclass

2 ответа

0

Я полагаю, способ справиться с этой проблемой - это вариация вашего решения. 2: создать конкретный интерфейс ICatcher со специальным уловом метода и сделать что-то вроде:

AnimalFactory::animal_type type = AnimalFactory::animal_type::cat;
std::shared_ptr<IAnimal> animal = myAnimalFactory.createAnimal(type);
(dynamic_cast<ICatcher*>(animal.get()))->catch();

Но здесь вы должны быть уверены, что dynamic_cast будет успешным или предоставит дополнительную проверку для этого.

Возможно, вам также было бы интересно, как эта проблема будет решена в COM с помощью суперинтерфейса IUnknown и его метода QueryInterface. Возможно реализовать локальную версию для этой архитектуры.

0

Я не думаю, что вы можете на самом деле бросить из shared_ptr в Cat, не так ли? Поэтому без знания вашей базы кода я написал небольшую тестовую программу,

#include <memory>
#include <string>
#include <iostream>

class IAnimal
{ 
public:
   virtual void makeSound(){}
};

class Cat : public IAnimal
{  
public:
    virtual void makeSound() { std::cout << "purr" << std::endl; }
    void catchMice(void){
        std::cout<<"mouse catched\n";
    }
};
class Dog : public IAnimal
{  
    virtual void makeSound() { std::cout << "bark" << std::endl; }
};

int main(int argc,char** argv){
    Cat* c = new Cat;
    std::shared_ptr<IAnimal> s(c);
    //you've basically got something of this sort don't you?
    s->makeSound();
    (static_cast<Cat*>(s.get()))->catchMice();
    return 0;
}

который должен делать то, что вы хотите. Я считаю, что вы можете иметь makeSound (void) как виртуальную функцию.

  • 0
    Пожалуйста, сфокусируйтесь на вопросе, вы можете использовать smart_pointer.get () для выполнения приведения или даже не использовать умный указатель. или используйте dynamic_pointer_cast; в любом случае, спасибо.
  • 0
    разве это не ответило на ваш вопрос? Вы хотите получить доступ к функции только дочернего класса через указатель базового класса, не так ли? Вы приводите его к указателю дочернего класса, и компилятор сгенерирует вызов функции во время компиляции.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню