I have a pretty simple question about the dynamic_cast
operator. I know this is used for run time type identification, i.e., to know about the object type at run time. But from your programming experience, can you please give a real scenario where you had to use this operator? What were the difficulties without using it?
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 .
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.
static_cast − This is used for the normal/ordinary type conversion. This is also the cast responsible for implicit type coersion and can also be called explicitly. You should use it in cases like converting float to int, char to int, etc. dynamic_cast −This cast is used for handling polymorphism.
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 .
Toy example
Noah's ark shall function as a container for different types of animals. As the ark itself is not concerned about the difference between monkeys, penguins, and mosquitoes, you define a class Animal
, derive the classes Monkey
, Penguin
, and Mosquito
from it, and store each of them as an Animal
in the ark.
Once the flood is over, Noah wants to distribute animals across earth to the places where they belong and hence needs additional knowledge about the generic animals stored in his ark. As one example, he can now try to dynamic_cast<>
each animal to a Penguin
in order to figure out which of the animals are penguins to be released in the Antarctic and which are not.
Real life example
We implemented an event monitoring framework, where an application would store runtime-generated events in a list. Event monitors would go through this list and examine those specific events they were interested in. Event types were OS-level things such as SYSCALL
, FUNCTIONCALL
, and INTERRUPT
.
Here, we stored all our specific events in a generic list of Event
instances. Monitors would then iterate over this list and dynamic_cast<>
the events they saw to those types they were interested in. All others (those that raise an exception) are ignored.
Question: Why can't you have a separate list for each event type?
Answer: You can do this, but it makes extending the system with new events as well as new monitors (aggregating multiple event types) harder, because everyone needs to be aware of the respective lists to check for.
A typical use case is the visitor pattern:
struct Element { virtual ~Element() { } void accept(Visitor & v) { v.visit(this); } }; struct Visitor { virtual void visit(Element * e) = 0; virtual ~Visitor() { } }; struct RedElement : Element { }; struct BlueElement : Element { }; struct FifthElement : Element { }; struct MyVisitor : Visitor { virtual void visit(Element * e) { if (RedElement * p = dynamic_cast<RedElement*>(e)) { // do things specific to Red } else if (BlueElement * p = dynamic_cast<BlueElement*>(e)) { // do things specific to Blue } else { // error: visitor doesn't know what to do with this element } } };
Now if you have some Element & e;
, you can make MyVisitor v;
and say e.accept(v)
.
The key design feature is that if you modify your Element
hierarchy, you only have to edit your visitors. The pattern is still fairly complex, and only recommended if you have a very stable class hierarchy of Element
s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With