142 lines
5.0 KiB
C
142 lines
5.0 KiB
C
/*
|
|
|
|
The other day we tracked a bad bug where a base class was been cast to
|
|
the wrong thing.
|
|
The reason why it happed was because we didn't have any RTTI (Run Time
|
|
Type Information) in place.
|
|
We also didn't want to use the one that it comes with the compiler for
|
|
fear that it will add "evil" code.
|
|
So after hitting that bug I decided to do my on RTTI. I wanted to be
|
|
simple and very fast.
|
|
This is what we use now. It looks kind of neat so I thought to share it.
|
|
Enjoy.
|
|
|
|
Tomas
|
|
tarce@zen-x.net
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
//==============================================================================
|
|
// RTTI
|
|
//==============================================================================
|
|
// Using the RTTI
|
|
//------------------------------------------------------------------------------
|
|
// struct base
|
|
// {
|
|
// CREATE_RTTI_BASE( base );
|
|
// };
|
|
//
|
|
// struct pepe : public base
|
|
// {
|
|
// CREATE_RTTI( pepe, base, base )
|
|
// void Normal( void ){}
|
|
// };
|
|
//
|
|
// struct super_pepe : public pepe
|
|
// {
|
|
// CREATE_RTTI( super_pepe, pepe, base )
|
|
// void Super( void ){}
|
|
// };
|
|
//
|
|
// void main( void )
|
|
// {
|
|
// super_pepe SP; // The original class
|
|
// base& B = SP; // Some generic base reference
|
|
//
|
|
// // We want to safely convert to pepe
|
|
// pepe& P = pepe::GetSaveType( B );
|
|
//
|
|
// // cast the base class right
|
|
// if( B.IsKindOf( super_pepe::GetRTTI() ) )
|
|
// {
|
|
// super_pepe& SP = super_pepe::GetSaveType( B );
|
|
// SP.Super();
|
|
// }
|
|
// else if( B.IsKindOf( pepe::GetRTTI() ) )
|
|
// {
|
|
// pepe& P = pepe::GetSaveType( B );
|
|
// P.Normal();
|
|
// }
|
|
// }
|
|
//==============================================================================
|
|
#define CREATE_RTTI( TYPE, BASE_CLASS )
|
|
#define CREATE_RTTI_BASE( TYPE )
|
|
|
|
struct RTTI
|
|
{
|
|
bool IsKindOf( const RTTI& RTTI ) const;
|
|
RTTI ( const char* pTypeName );
|
|
RTTI ( const char* pTypeName, const RTTI& RTTI );
|
|
|
|
const char* pType; // This is not really need it, just useful in debugger.
|
|
const RTTI& Next;
|
|
};
|
|
|
|
//==============================================================================
|
|
// IMPLEMENTATION
|
|
//==============================================================================
|
|
#pragma warning( push )
|
|
#pragma warning( disable : 4355 ) // warning 'this' used in base member initializer list
|
|
#undef CREATE_RTTI
|
|
#undef CREATE_RTTI_BASE
|
|
|
|
inline RTTI::RTTI( const char* pTypeName ) :
|
|
pType(pTypeName), Next( *this ){}
|
|
|
|
inline RTTI::RTTI( const char* pTypeName, const RTTI& RTTI ) :
|
|
pType(pTypeName), Next( RTTI ){}
|
|
|
|
inline bool RTTI::IsKindOf( const RTTI& RTTI ) const
|
|
{
|
|
const RTTI* p = this;
|
|
do
|
|
{
|
|
if( p == &RTTI ) return true;
|
|
if( p == &p->Next ) break;
|
|
p = &p->Next;
|
|
|
|
} while(1);
|
|
return false;
|
|
}
|
|
|
|
#define PRIVATE_RTTI_FUNCTION_SET( TYPE, BASE_CLASS ) \
|
|
virtual inline const RTTI& GetObjectRTTI( void ) const \
|
|
{ \
|
|
return TYPE::GetRTTI(); \
|
|
} \
|
|
inline const bool IsKindOf( const RTTI& RTTI ) const \
|
|
{ \
|
|
return GetObjectRTTI().IsKindOf( RTTI ); \
|
|
} \
|
|
static inline TYPE& GetSaveType( BASE_CLASS& Object ) \
|
|
{ \
|
|
assert( Object.IsKindOf(TYPE::GetRTTI()) ); \
|
|
return *((TYPE*)&Object); \
|
|
} \
|
|
static inline const TYPE& GetSaveType( const BASE_CLASS& Object ) \
|
|
{ \
|
|
assert( Object.IsKindOf(TYPE::GetRTTI()) ); \
|
|
return *((const TYPE*)&Object); \
|
|
}
|
|
|
|
#define CREATE_RTTI( TYPE, TYPE_PARENT, BASE_CLASS ) \
|
|
static inline const RTTI& GetRTTI( void ) \
|
|
{ \
|
|
static RTTI s_RTTI( #TYPE, TYPE_PARENT::GetRTTI() ); \
|
|
return s_RTTI; \
|
|
} \
|
|
PRIVATE_RTTI_FUNCTION_SET(TYPE,BASE_CLASS)
|
|
|
|
#define CREATE_RTTI_BASE( TYPE ) \
|
|
static inline const RTTI& GetRTTI( void ) \
|
|
{ \
|
|
static RTTI s_RTTI( #TYPE ); \
|
|
return s_RTTI; \
|
|
} \
|
|
PRIVATE_RTTI_FUNCTION_SET(TYPE,TYPE)
|
|
|
|
#pragma warning( pop )
|