Monday 12 November 2007

RTTI : How to import and export interfaces from classes in a cheap and easy way

Hi,

I have been working on this for some time and tried different solutions but this one I am posting here is the one I like the most. It has some problems tho, as it does not work for DLL's unless you ask the DLL itself for the interface you are requesting, but in the general case, it is very simple to use and does not add any runtime cost (apart from a small amount of memory for each interface type).

Here is the code (I have formatted it a bit to fit into the blog, but I can send you the original file upon request to my email address)

That's all for now!

Cheers!

J.

//****************************************************************************
// Templatized RTTI
// Date(dd/mm/yyy): 22/06/2007
// Author: Jaime C. Olivares - cherno.olivares#gmailDOTYOUKNOW
//****************************************************************************

#ifndef _NW_RTTI_H_
#define _NW_RTTI_H_

typedef intptr_t NWRttiTypeId;

//----------------------------------------------------------------------------
// The RTTI itself
// It is a simple idea:
// The address of a static member of a templatized class
//----------------------------------------------------------------------------
template '<'class T'>' class NWRtti
{
public:
static inline NWRttiTypeId getTypeId();

private:
static int mDummyVar;
};

template '<'class T'>' /*static*/ int NWRtti'<'T'>'::mDummyVar = 0;

template '<'class T'>' /*static*/ inline NWRttiTypeId NWRtti'<'T'>'::getTypeId()
{
// avoids compiler to optimize and return same addr for all types
++mDummyVar;

// return the address of this member fn as RTTI
return (NWRttiTypeId)&getTypeId;
}

#define RTTI_TYPE_ID(T) static inline NWRttiTypeId getTypeId() \
{return NWRtti'<'T'>'::getTypeId();} // use this macro to have TypeId in classes

//----------------------------------------------------------------------------
// Helper class to inherit from by classes exporting interfaces
//----------------------------------------------------------------------------
class NWInterfaceProvider
{
public:
NWInterfaceProvider() {}
virtual ~NWInterfaceProvider() {}

template '<'class T'>' inline T * getInterface();

protected:
//derived classes must implement this fn
virtual void * getInterfaceFromID(NWRttiTypeId _typeId)=0;

template '<'class T'>' inline T * NWInterfaceProvider::getInterface()
{
return (T *) getInterfaceFromID(NWRtti'<'T'>'::getTypeId());
}

#endif //_NW_RTTI_H_

//****************************************************************************
// Example
//****************************************************************************

//----------------------------------------------------------------------------
// Some interfaces we want share
//----------------------------------------------------------------------------
//struct IEncoder
//{
// virtual unsigned int getEncodingCaps()=0;
// ...
//
// RTTI_TYPE_ID(IEncoder)
//};
//
//struct IVideoEncoder
//{
// virtual unsigned int getVideoEncoderCaps()=0;
// ...
//
// RTTI_TYPE_ID(IVideoEncoder)
//}
//
//struct IVideoEncoderH264
//{
// virtual int getVideoCodecH264KeyFramePeriod()=0;
// ...
//
// RTTI_TYPE_ID(IVideoEncoderH264)
//}

//----------------------------------------------------------------------------
// The exporter (or it's base class if any) inherits from NWInterfaceProvider
//----------------------------------------------------------------------------
//class VideoEncoderDicasH264 : public NWInterfaceProvider
//{
//public:
// ...
//
//protected:
// virtual void * getInterfaceFromID(NWRttiTypeId _iid);
// // Implement this fn to provide the valid interfaces
// //private:
// ...
//};
//----------------------------------------------------------------------------
// Exporter class fn (this class inherits from the interface): //----------------------------------------------------------------------------
// /*virtual*/ void * VideoEncoderDicasH264::getInterfaceFromID(NWRttiTypeId _iid)
//{
// if(_iid == IVideoEncoderH264::getTypeId())
// {
// return static_cast'<'IVideoEncoderH264*'>'(this);
// }
// else if(_iid == IVideoEncoder::getTypeId())
// {
// return static_cast'<'IVideoEncoder*'>'(this);
// }
// else if(_iid == IEncoder::getTypeId())
// {
// return static_cast'<'IEncoder*'>'(this);
// }
//
// return NULL; // if no base class just return NULL or
// //return Inherited::getInterfaceFromID(_iid); // if base class has other interfaces
//}

//----------------------------------------------------------------------------
// External use
//----------------------------------------------------------------------------
//void test()
//{
// VideoEncoderDicasH264 encoderObj;
//
// encoderObj.init();
//
// IEncoder * encoder = encoderObj.getInterface();
// if(encoder)
// {
// unsigned int caps = encoder->getEncodingCaps();
// }
//
// IVideoEncoder * videoEncoder = encoderObj.getInterface'<'IVideoEncoder'>'();
// if(videoEncoder)
// {
// unsigned int caps = videoEncoder->getVideoEncoderCaps();
// }
//
// IVideoEncoderH264 * encH264 = encoderObj.getInterface'<'IVideoEncoderH264'>'();
// if(videoEncoderH264)
// {
// int keyFramePeriod = videoEncoderH264->getVideoCodecH264KeyFramePeriod();
// }
//
// encoderObj.shutdown();
//}

No comments: