Почему dynamic cast зло или нет? Должен ли я использовать dynamic cast в этом случае?

некоторые говорят the use of dynamic_cast often means bad design and dynamic_cast can be replaced by virtual functions

  1. почему использование dynamic_cast считается плохой дизайн?
  2. Предположим, у меня есть имя функции func(Animal* animal, int animalType) реализация в func как:

    bool func(Animal* animal, int animalType)
    {
      ...
      /* Animal is the base class of Bear, Panda, Fish ....
      dynamic_cast animal to real animals(Bear, Panda, Fish...) 
      according to animalType. Do some processing with this specific
      type of animal, using its additional information beyond base 
      class Animal. */
    }
    

это дело правильное использование dynamic_cast?

3 ответов


это точно неправильное место для использования dynamic_cast. Вы должны использовать полиморфизм. Каждый из Animal классы должны иметь , например, process и здесь вы должны просто позвонить animal->process().

class Animal{
    virtual void Process() = 0;
}
class Cat:public Animal{
    void Process() {cout<<" I am a tiny cat";}
}
class Bear :public Animal{
    void Process(){cout<<"I am a big bear";
}

void func(Animal* animal){
    if(animal != NULL) animal -> Process();
}

другие проблемы.

что это animal - это собака, но из-за ошибки animal_type говорит, что ее кошка?

бывают моменты, когда static_cast необходимо, и по возможности используйте его вместо динамического приведения. Dynamic cast имеет дополнительную производительность стоимость, которую статический бросок не делает. Для этого вам нужно быть уверенным, что вы знаете тип, который входит, так как static_cast более небезопасным.

p.s. по крайней мере,animal_type должен быть членом Animal.


теоретически, отливка вниз никогда не должна быть необходима. Вместо этого вы должны адаптировать базовый класс, чтобы включить необходимые virtual метод.

на практике вы сталкиваетесь с такими вещами, как сторонние библиотеки. В этом случае изменение базового класса не является опцией, и поэтому вы можете быть вынуждены использовать dynamic_cast...

вернемся к вашему примеру:

class Animal {
public:
    // starts moving toward `p`,
    // throws a `Unreachable` exception if `p` cannot be reached at the moment.
    virtual void moveToward(Point const& p) = 0;
}; // class Animal

и затем:

bool move(Animal& animal, Point const& p) {
    try {
        animal.moveToward(p);
        return true;
    } catch (Unreachable const& e) {
        LOG(animal.id() << " cannot reach " << p << ": " << e.what());
    }

    return false;
} // move

когда вы используете downcasting, dynamic_cast хорош, потому что он ограничивает вас в downcast до нерелевантного типа. См. этой.