StillLearning
StillLearning

Reputation: 77

Best way to id an inherited class

I'm working on a small framework in C++ to use in some of my projects, to statically link against as a utility library of sorts. I guess you could compare it to a more domain-specific to my personal needs, and simpler library like juce. This is as much a learning and experience exercise as anything else, so I'd like to take the time to do things properly and understand the techniques I apply. I'm currently working in linux, but aiming for the code to be portable, so this will allow me to write any platform specific code to an interface.

At the moment I'm working on a basic messaging system, which I would like to allow for messages that include objects of various types. My initial thought was like so:

class Message {
  virtual std::string type;
};
class DataMessage : Message {
  std::vector<std::string> *data;
};

My question is, what is the best way to identify that a Message is a DataMessage, and either cast it to its actual type, or access the data it contains?

I can use a string for the type like above, but that doesn't guarantee each subclass will actually have a unique type id. Also, I wonder if the overhead of string processing would be slower than an alternative (could I extend an enum, for example?).

As for accessing the data, if I can cast the Message to its proper type, this is not an issue. Otherwise, I could add a virtual function to the base class as either an accessor (but then how do I have it use a different return type to the one specified in the base class? What if the class doesn't need any additional data?), or as a worker function that acts on the data (but I would rather have it just as a data passing mechanism between classes, versus a callback style framework).

Any suggestions, alternatives or links are much appreciated. Discussion of different approaches would be awesome!

Thanks in advance guys.

Upvotes: 1

Views: 335

Answers (3)

Asha
Asha

Reputation: 11232

You can use DataMessage* pDataMessage = dynamic_cast<DataMessage*>(pMessage). The pDataMessage will be valid only if pMessage is a DataMessage object. Otherwise it will be NULL.

Upvotes: 2

Alok Save
Alok Save

Reputation: 206546

My question is, what is the best way to identify that a Message is a DataMessage, and either cast it to its actual type, or access the data it contains?

You should not do that!
Once you do so you are making your design weak. You essentially end up breaking one of the basic principle of SOLID paradigm, the "Liskov Substitution Principle".
Note that if anywhere in your code if you perform actions depending on the concrete type of an object you are coding to the implementation and not the interface. The basic design guideline is:
"Code to the Interface not the Implementation."
If you start coding to concrete types your code becomes more difficult to maintain and more tightly coupled.Each time you would want to add a new derived class your code even breaks down further and you lose the generosity.

You should instead rely on Polymorphism to do the task for you. You should implement virtual methods in your base class and override them appropriately in derived classes. You only just need to call such a method and the run-time would call appropriate method in each of the classes because the run-time knows what the concrete type is.Important is that the code you write need not know the type.

You might want to check out some good patterns like Template method pattern which might serve you well.

Upvotes: 3

Kirill Kobelev
Kirill Kobelev

Reputation: 10557

Use the typeid operator. This is part of the C++ RTTI. Almost all compilers support it. Although if this is your own framework, approach with a data field (better of a enum type) is also not that bad.

Upvotes: 2

Related Questions