开发者

C++ casting a base pointer to an interface pointer

开发者 https://www.devze.com 2023-03-25 23:07 出处:网络
Here is some pseudo code of my setup: class IMyClass { ... }; // pure virtual class class CMyBaseClass { .... };

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 passing this.
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号