RTTI is never straight forward without knowing why you want to use it. It seems to be bad style to utilize it just for accessing a component because the work done in behind the scenes is more intensive than the result can be useful. Think of a AAA game of millions of components that live in the game, if you need to query the component-ID every for even thousands of them every frame, you'll get what Unity makes slow these days, massive framedrops caused by lookups.
AAA games and even Unity itself don't query a component's inheritance chain, instead they add generated ID tables to every component to speed lookups up or limit the amount of components that much that you can have a single 16/32 or 64 bit value to represent an entity's components via an on/off switch. Why? Just because memory efficiency on the CPU.
You don't want to query each component on it's own and process it, you want a system o operate an a set of components who's entities match a given pattern. For example a movement system operates on entites that have the transform and animation component attached, in a single for loop.
karlmar said:
Ideally the interface should revolve to asking via a static call
Our engine's straight forward solution is a compiler macro trick and a static/ global template function. Using the __PRETTY_FUNCTION__ and similar macros in other compilers result in a string representation of the function currently called. If you define a template function, the compiler will create an instance of that function for every template type used in your code and so the output of __PRETTY_FUNCTION__ changes to reflect the exact type name of ANY given type in the entire C++ environment.
Something like
template<typename T> inline const char* gfn()
{
return __PRETTY_FUNCTION__;
}
using namespace std;
gfn<string>();
results in
"char* const gfn<std::basic_string<char>>()"
We are running a short hash function like FNV32b over the resulting string to obtain our own unique type IDs for whatever is requested and base everything else on that ID.
On the other hand we also have generated type information like in C#.NET Reflection. This way we can iterate members, properties and functions of our types, obtain pointers to them and also feed a type ID into a generator class to create instances on demand.
A very usefull thing our Type System is capable for is the anonymous interface wrapper. This is a quite useful trick stolen from Typescrypt: as long as certain type exists that implements certain functions defined by an interface, that type's instances can be converted into and used by APIs that require exactly that interface without every inheriting from the interface type.
Our Type System is meant to be used in editor code for example but also in release code if instances are serialized into savegames for example