Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is dynamic_cast evil or not ? Should I use dynamic_cast in this case?

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?

like image 858
Gary Gauh Avatar asked Aug 26 '13 08:08

Gary Gauh


People also ask

Should I use dynamic_cast?

This cast is used for handling polymorphism. You only need to use it when you're casting to a derived class. This is exclusively to be used in inheritence when you cast from base class to derived class.

What is the use of dynamic_cast?

The primary purpose for the dynamic_cast operator is to perform type-safe downcasts. A downcast is the conversion of a pointer or reference to a class A to a pointer or reference to a class B , where class A is a base class of B .

Is dynamic_cast a code smell?

Yes, dynamic_cast is a code smell, but so is adding functions that try to make it look like you have a good polymorphic interface but are actually equal to a dynamic_cast i.e. stuff like can_put_on_board .

Is Static_cast faster than dynamic_cast?

While typeid + static_cast is faster than dynamic_cast , not having to switch on the runtime type of the object is faster than any of them. Save this answer.


2 Answers

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.

like image 168
Karthik T Avatar answered Oct 25 '22 06:10

Karthik T


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
like image 44
Matthieu M. Avatar answered Oct 25 '22 06:10

Matthieu M.