Question

Some say the use of dynamic_cast often means bad design and dynamic_cast can be replaced by virtual functions

  1. why is the use of dynamic_cast considered bad design?
  2. Suppose I have I function name func(Animal* animal, int animalType) , the implementation in func is like:

    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. */
    }
    

Is this case a proper use of dynamic_cast?

Was it helpful?

Solution

This is EXACTLY the wrong place to use dynamic_cast. You should be using polymorphism. Each of the Animal classes should have a virtual function, say, process and here you should just call animal->process().

class Animal {
    virtual void Process() = 0;
}

class Cat : public Animal {
    void Process() { std::cout << " I am a tiny cat"; }
}

class Bear : public Animal {
    void Process() { std::cout << "I am a big bear"; }
}

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

Other problems.

What if animal is a Dog, but due to a bug animal_type says its a Cat?

There are times when static_cast is necessary, and if possible use it instead of dynamic_cast. Dynamic cast has the additional performance cost that static cast does not. For this, you need to be sure you know the type that is coming in, since static_cast is more unsafe.

At the very least, animal_type should be a member of Animal.

OTHER TIPS

In theory, down-casting should never be necessary. Instead you should adapt the base class to include the necessary virtual method.

In practice, you encounter things such as 3rd party libraries. In this case, modifying the base class is not an option and thus you may be forced into using dynamic_cast...

Back to your example:

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

And then:

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

When you use downcasting, dynamic_cast is good, because it restricts you to downcast to irrelevant type. Please refer this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top