Here is some pseudo code of my setup:
class IMyClass { ... }; // pure virtual class
class CMyBaseClass { .... };
class CMyClass : public CMyBaseClass, public IMyClass { ... }
Then I have collection of CMyBaseClass*. I have custom RTTI that allows me to find out if a class implements given interface. So I can find which of the objects have IMyClass implementation. My problem is that I can't cast it to that interface. I don't want to 开发者_运维百科use standard RTTI and dynamic cast.
I'm thinking in my custom RTTI to store some pointer diffs for casting between pair of classes, but I haven't figure out implementation that makes me happy.
Any other solutions?
Well, if you insist in not using the language RTTI, you can use just like the old COM: make all your classes or interfaces derive from the following interface:
class IMyCast // similar to IUnknown
{
public:
virtual void *CastTo(interfaceId_t id) = 0; //Similar to IUnknown::QueryInterface
};
Now in your CMyClass:
class CMyClass : public CMyBaseClass, public IMyClass
{
//...
void *CastTo(interfaceId_t id)
{
switch (id)
{
case IMyClass_id: //or whatever
return static_cast<IMyClass*>(this);
//...other cases
default:
throw std::bad_cast(); //or return NULL
}
}
};
Then in the user code:
CMyBaseClass *obj;
IMyClass *my = static_cast<IMyClass*>(obj->CastTo(IMyClass_id));
Probably you'll need to augment your custom RTTI; at least this is what I did in pretty much the same situation. Instead of using pointer diffs, my solution instantiates a "caster" function template for the necessary (Class, Interface) pairs. It's something like this:
- All interfaces have a unique int id. For this a MyInterface needs to be derived from InterfaceBase. The id is assigned automatically on the first MyInterface::GetId() call.
- The implementor of MyClass (that implements MyInterface) needs to add an IMPLEMENTS(MyClass, MyInterface) macro in a .cpp file.
- The macro instantiates a
void* GetInterface<C, I>(void*)
function, and then registers a pointer to this function in an interfaceId -> GetInterface-function map (that belongs to class C). This function casts its argument into C*, then the C* into I*, and finally back to void*. (The hacking with void*'s is necessary so that all these functions have the same signature, thus they can be stored in a map.) - To get an interface, the user needs to call a myObject->GetInterface() function, implemented in CMyBaseClass. It finds the map that belongs to the dynamic class of the
this
object, looks up the appropriate caster function based on I::GetId(), and calls it passingthis
.
精彩评论