How do I avoid using dynamic_cast when implementing external actions?

dynamic_cast is pure evil. Everyone knows this. Only noobs use dynamic_cast. :)

What I've read about dynamic_cast. Many topics on stackoverflow say "use virtual functions in this case".

I have some interfaces that reflect the capabilities of objects. Let them talk:

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 can implement them:

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

      

In the GUI layer, I would like to enable / disable or show / hide buttons depending on what functionality is implemented by an object selected by the user:

Object *selected_object;

      

I would do it this 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 others (more experienced) say, this is clear evidence of poor design.

What would be a good design in this case?

And no, I don't want a bunch of virtual functions in mine Object

. I would like to add a new interface and new classes that implement it (and new buttons) without touching Object

.

Also a virtual function like get_buttons

in Object

doesn't seem good to me. Mine Object

doesn't know anything about GUI, buttons, etc.

A function like get_type

that that returns some enumeration might also solve the problem, but I don't understand why the self-employed RTTI substitute should be better than the native one (ok, it would be faster, but it doesn't. It doesn't matter in this case.

+3


source to share


1 answer


You already hit your nail on the head: you are trying to get type information from an "opaque" object type *. Using dynamic_cast is just a simple hack. Perhaps your problem is that C ++ doesn't have what you want: good type information. But here are some thoughts.

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

Secondly, some other part might be aware of the specific type of object and can help create your visual display so that the object * is no longer a bottleneck.



Third, if you do use something like the option you are talking about, I think you will find that a type id of some kind versus using dynamic_cast is more useful since you can create tables to view for example visual builders.

Also, you were wondering why the information on scooter and RTTI? If you are very concerned about performance, RTTI is included for all types, which means everything can be a hit; the scooter option allows you to refuse (due to the complexity). Also, you won't need to push this to others if you are writing a library pulled through source, etc.

+1


source







All Articles