As the title suggests, I am looking for a fast way of runtime typechecking. To illustrate my problem, imagine you have a class hierarchy like the following:
Base
/ \
A D
/ \ / \
C B F E
\ /
G
My program holds all instances of any class in a single list as Base_ptr because all these classes share common tasks. Now at some point some derived classes will need to know about the existence of an instance of another class. So far so good, I know about dynamic_cast and the typeid()-operator, but both have some mayor drawbacks:
- dynamic_cast consumes a lot of processing time if the types are incompatible (e.g. try to cast instances of E to C)
- typeid() does not work in "isTypeOrSubtype"-cases, e.g. you need all instances of D or derived from D (so Es, Fs and Gs as well)
The ideal solution would be some kind of "isTypeOrSubtype"-test and only casting, if this test returns successfully. I got an own approach with some macro definitions and precalculated classname hashes, but it is very ugly and hardly maintainable. So I am looking for a cleaner and faster way of dynamic type and subtype checking that can check far more than 20million times per second.
If your program knows about all the sub types that will be tested against, you can use a virtual interface that returns a pointer to the sub type. As noted by downvotes and comments, this is not the most flexible approach, since it requires the base class have knowledge of all the derived classes. However, it is very fast. So there is a trade off of flexibility to performance.
On IDEONE, the suggested technique is 20 to 50 times faster than using dynamic cast.1 The implementation uses macros to allow a new class to be added to a single place, and the proper expansions to the base class occur in an automated way after that.
If flexibility has a higher value than performance, then a slightly less performant solution is to use a
map
to associate types and corresponding pointer values (having the pointer values removes the need for a dynamic cast). Themap
instance is maintained in the base class, and the associations are made by the constructors of the subclasses. Whether a regularmap
or aunordered_map
is used will depend on how many subclasses virtually inherit the base class. I would presume the numbers will be small, so a regularmap
should suffice.On IDEONE, this second suggestion is 10 to 30 times faster the using dynamic cast. I don't think IDEONE compiles with optimizations, so I would expect the times to be closer to the first suggestion on a production build. The mechanism as implemented uses
typeid(...).name()
as the key to the map.2