Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid using dynamic_cast, when implementing external actions?

dynamic_cast is pure evil. Everybody knows it. Only noobs use dynamic_cast. :)

That's what I read about dynamic_cast. Many topics on stackoverflow say "use virtual functions in this case".

I've got some interfaces that reflect capabilities of objects. Let's say:

class IRotatable
{
  virtual void set_absolute_angle(float radians) =0;
  virtual void rotate_by(float radians) =0;
};

class IMovable
{
  virtual void set_position(Position) =0;
};

and a base for a set of classes that may implement them:

class Object
{
  virtual ~Object() {}
};

In GUI layer I would like to enable/disable or show/hide buttons depending on which features are implemented by the object selected by the user:

Object *selected_object;

I would do it in such a way (simplified):

button_that_rotates.enabled = (dynamic_cast<IRotatable*>(selected_object) != nullptr);

(...)

void execute_rotation(float angle)
{
  if(auto rotatable = dynamic_cast<IRotatable*>(selected_object))
  {
    rotatable->rotate_by(angle);
  }
}

but as other (more experienced ones) say, it is obvious evidence of bad design.

What would be a good design in this case?

And no, I don't want a bunch of virtual functions in my Object. I would like to be able to add new interface and new classes that implement it (and new buttons) without touching Object.

Also virtual function like get_buttons in by Object doesn't seem good for me. My Object knows completely nothing about GUI, buttons and such things.

A function like get_type that returns some enum could also solve a problem, but I don't see why self-implemented substitute of RTTI should be better than the native one (ok, it would be faster, but it doesn't matter in this case).

like image 504
peper0 Avatar asked Dec 07 '25 21:12

peper0


1 Answers

You've already hit the nail on the head: you're trying to get type information from an "opaque" Object* type. Using dynamic_cast is just a hack to get there. Arguably your problem is actually that C++ doesn't have what you want: good type information. But here's some thoughts.

First, if you're going to a lot of this sort of thing, you may find that you are actually shifting away from typical inheritance and your program may be better suited to a component based design pattern, as is more common in video games. There you often have a somewhat opaque GameObject at the root and want to know what "components" it has. Unity does this sort of thing and they have nice editor windows based on components attached to the GameObject; but C# also has nice type info.

Second, some other part of the might know about the concrete type of the object and can help build your visual display, causing the Object* to no longer be a bottleneck.

Third, if you do go with something like the option you're talking about, I think you will find having type id of some sort vs. the use of dynamic_cast to be more helpful, since you can then build tables to look up types to say, visual builders.

Also, you were wondering why a self-rolled type info vs. RTTI? If you are quite concerned about performance, RTTI is on for all types and that means everything could take a hit; the self-rolled option allows for opt-in (at the cost of complexity). Additionally you won't need to push this onto others if you're writing a library pulled in via source, etc.

like image 72
J Trana Avatar answered Dec 10 '25 09:12

J Trana



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!