dynamic_cast or redundancy?

138 views Asked by At

In my system low hiearchy objects talk to the high hiearchy object via calling function of the +1 level hiearchy object, which calls a function of the +1 level hiearchy object, etc etc etc, until the function calling stops at the recipent.

There is a Message abstract class, and there are lots of derivated classes, which hold different kinds of datas. Like:

  • FruitMessage: string, int

  • CoordinateMessage: float, float, float

etc etc

And those methods I mentioned before want Message objects so this chaincalling is done through one kind of method instead of creating methods for all of the Message types.

The problem comes, when the recipent receives the Message object.

The recipent wants to know what's in that message, so it can process receives message as the message type requires it.

(like it decreases the integer by 1 in FruitMessages, divides the coordinates in CoordinateMessages, etc.)

Currently I have two ideas, but maybe none of them is correct and I should use a third one. (tell me please)

  • The recipent dynamic_casts it while it doesn't the correct type.

  • Message has an enum field called MessageType, which is initalized in the derived class' constructor to the correct value, so the recipent just uses a switch-case during the process.

My question is that is it worth the redundancy?

  • dynamic_cast is slower than the integer check

  • but every time I create a new Message class I have to create a new enum value.

What should I do?

2

There are 2 answers

0
user3237732 On

Both ways are OK. Redundancy vs speed is very common problem in Software development. I would choose dynamic_cast as redundancy is the first step to bugs, but it's really up to you and depends on your performance requirements. I saw very similar problem while working with Akka, they usually use dynamic_cast (I mean java/scala analogues)

4
Joseph Thomson On

I would recommend using the typeid operator to check the type of the message. This way, you avoid repeatedly calling dynamic_cast until you get the correct type.

void process_message(Message const& msg) {
  if (typeid(msg) == typeid(FruitMessage)) {
    auto& fruit_msg = static_cast<FruitMessage const&>(msg);
    …
  }
}

Even better, you could use the C++17 std::any container type. An any object can be copied around like a non-polymorphic value, and does not require the use of a virtual base class. If you don't have access to a C++17 library implementation, you could use boost::any instead.

void process_message(std::any const& msg) {
  if (msg.type() == typeid(FruitMessage)) {
    auto fruit_msg = std::any_cast<FruitMessage>(msg);
    …
  }
}

As for whether using an enum field would be faster than typeid or any, you'll have to do the benchmarking yourself.