Archived

This topic is now archived and is closed to further replies.

Succinct

Run Time Type Identification and static member functions

Recommended Posts

I've implemented an RTTI system (single inheritence) similar in vein to what David Eberly does in his book, "3d Game Engine Design". Each class gets itself a static RTTI object that contains a string representing the class's name and a link to the parent class's static RTTI object. My main motivation for this is to aid in streaming/serializing of objects. The RTTI information stores an object's name, and it is possible to dynamically map RTTI objects to factory functions for each object type. Each object type statically adds itself to this RTTI to factory function map, so all I need is an RTTI object to create any object type. Finding an RTTI from a string is trivial. Another reason is that if each object can write it's own name to disk, I won't need to write a numeric object identifier that needs to be switch/cased eventually. I can add new objects just by adding DLL's that can create objects from their own RTTI objects because they all automatically add the location of their factory function based on their RTTI. For the factory functions, first I create a map of RTTI objects to creation functions. Each class adds an entry to the map for it's own RTTI object and its creation function. That way, given an RTTI object, using the map, I can create objects of that type. I also have a similar map that maps strings to RTTI objects, so, given a string (possibly read in from a file), I can dynamically create objects of that type as well, because the strings map to RTTIs, and the RTTIs map to factory functions:
        
typedef TObject* (*TFactoryFunc)( void ); // typedef for the pointer to factory function

typedef std::map<const TRTTI*,TFactoryFunc> TFactoryFuncMap; // maps TRTTI objects to their factory functions

typedef std::map<TString,const TRTTI*> TNameMap; // maps type names to TRTTI objects

//---------------------------------------------------------------------------


TObject* TObject::CreateObject( const TRTTI* c_pRTTI ) // a static, private function

{
    TFactoryFunc f = ms_FactoryFuncMap[c_pRTTI];
    if( f )
        return f();
    else
        return 0;
}
//---------------------------------------------------------------------------


TObject* TObject::CreateObject( const TString& TypeName ) // a static, public function - this is the main function used in the program to create an object from a string

{
    return CreateObject( LookUpName( TypeName ) );
}
//---------------------------------------------------------------------------


const TRTTI* TObject::LookUpName( const TString& Name )
{
    return ms_NameMap[Name];
}
//---------------------------------------------------------------------------

  
This works fine for my factory functions, but in order to call a factory function given just a string (and from that an RTTI), I need to map the RTTI to the function pointer. I would have to have a separate RTTI-function pointer map for each function. That's a little bit much though, I feel, to do for even 5 functions. In my hirearchy, each class gets a few standard static member functions, such as TObject::CreateInstance and TDerivedObject::CreateInstance (my factory functions), TObject::GetSize and TDerivedObject::GetSize (which returns the size of an object in memory), TObject::GetRecordSize and TDerivedObject::GetRecordSize (which returns the size an object occupies on disk), and possibly others. My problem is figuring out a general solution to call a particular static member function given only a string representing the class's name and which function I want to call. Do I absolutely have to create maps for each function, or can someone think of some way to use the string to find the function? I'm thinking something with macros (as that's how a lot of my RTTI is implemented anyway), but I can't see any way of stripping off the quote characters if even if I could actually expand a string variable. Thank you for your time, -- Succinct [edited by - Succinct on May 1, 2002 8:01:18 PM]

Share this post


Link to post
Share on other sites
What about serializing a FOURCC or a GUID instead of a string? (IPersist). Then the map/hash is at least reasonably efficient (CoCreateInstance isn't, but a custom abstract factory could be).

Or you can hash the string and hope there's no collisions...


Or just use RTTI - the only serious disadvantage is that it's not run-time interoperable (RTI). All the popular PC C++ compilers support RTTI now, and Comdeau will take care of the rest. Odds are low you're going to implement something faster than the built-in RTTI unless you cut out the fat (that's the string part which you seem to want .

We need an extention for, and a way to tell RTTI to use a particular GUID for a given class/interface. MSVC has this at compile-time by-way-of:
struct __declspec(uuid("000c0310-0000-0000-c000-000000000046")) X;
X x;
__uuidof(x);
but you need a code-up function to call to get it at run-time (IPersist::GetClassID).

An automatic implementation would be nice. Actually I think I might pay vs.languages a visit...

[edited by - Magmai Kai Holmlor on May 1, 2002 8:43:12 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Succinct
My main motivation for this is to aid in streaming/serializing of objects.



I haven''t read "3d Game engine design" (althought it''s gathering dust on my bookshelf) yet but if you are serializing objects, I would suggest your base object interfaces have virtual methods for loading/saving.

The factory should not be overly concerned with the type of function it is. Doing otherwise is almost as good as down casting, no?

For creation. You can use the virtual constructor idiom. Check C++ Faqs).

Share this post


Link to post
Share on other sites