Files CCore/inc/InterfaceHost.h CCore/src/InterfaceHost.cpp
In C++ by tradition we implement interfaces using abstract classes.
struct SomeInterface { virtual void some_method()=0; };
Then we implement this interface in some derived class.
class SomeClass : public SomeInterface , public SomeBase { public: virtual void some_method(); };
Once we have a base object pointer we can retrieve the interface using the dynamic_cast.
SomeBase *pbase=....; SomeInterface *pif=dynamic_cast<SomeInterface *>(pbase);
This approach is simple, but have one big disadvantage. You have to implement interface in the object. You cannot borrow the interface from another object.
class SomeClass : public SomeBase { class InnerClass : public SomeInterface // no way to get this interface from SomeBase pointer { .... }; InnerClass inner; public: };
InterfaceHost is a tool to solve this problem.
struct InterfaceHost
{
virtual void requestInterface(InterfaceCaster &caster) { caster.cast(this); }
template <class T>
T * pickInterface()
{
InterfaceCasterTo<T> caster;
requestInterface(caster);
return caster;
}
template <class T>
T * takeInterface(StrLen from)
{
T *ret=pickInterface<T>();
if( !ret ) GuardNoInterface(from,GetInterfaceName<T>());
return ret;
}
};
It is a class with one virtual method requestInterface() and two helper methods pickInterface() and takeInterface().
The method requestInterface() has default implementation, this variant takes the required interface from the host class. But you can override this behavior in a derived class to take interfaces from another sources:
// // interface is retrieved from the host class // class SimpleClass : public InterfaceHost , public SomeInterface { public: virtual void some_method(); }; // // interface is retrieved from the inner class // class AdvancedClass : public InterfaceHost { class InnerClass : public SomeInterface { public: virtual void some_method(); }; InnerClass inner; public: virtual void requestInterface(InterfaceCaster &caster) { caster.cast(&inner); } }; // // interface is retrieved from multiple sources // class MultiClass : public InterfaceHost { class InnerClass : public SomeInterface { public: virtual void some_method(); }; InnerClass inner; OuterClass *outer; public: virtual void requestInterface(InterfaceCaster &caster) { if( caster.getTypeNumber().oneOf<SomeInterface>() ) { caster.cast(&inner); } else { outer->requestInterface(caster); } } };
Yoy may do nothing to reject some interface request.
The "caster" interface InterfaceCaster has two methods.
struct InterfaceCaster
{
virtual void cast(InterfaceHost *obj)=0;
virtual TypeNumber getTypeNumber()=0;
};
cast() performs the dynamic_cast from the given pointer to the requested interface.
getTypeNumber() returns the type number of the requested interface. You can use one to dispatch the cast operation between multiple sources. You must assign a Unid to the interface class.
T * pickInterface<T>() requests the specific interface, given by the template parameter. If the interface is not supported null is returned.
T * takeInterface<T>(StrLen from) does the same, but throw an exception if the interface is not supported. The argument from is used to report the requester. To throw the exception the function GuardNoInterface() is used, the argument name is created using the class GetInterfaceName<T>. This class takes the inner constant T::InterfaceName or the name "<Unknown interface>", if such constant does not exist.
/* functions */ void GuardNoInterface(StrLen from,StrLen name); /* struct GetInterfaceName<T> */ template <class T> struct GetInterfaceName : StrLen { GetInterfaceName(); };