C++将基指针转换为接口指针

发布于 2024-11-28 08:31:13 字数 391 浏览 1 评论 0原文

这是我的设置的一些伪代码:

class IMyClass { ... }; // pure virtual class
class CMyBaseClass { .... };
class CMyClass : public CMyBaseClass, public IMyClass { ... }

然后我有 CMyBaseClass* 的集合。我有自定义 RTTI,它允许我查明某个类是否实现给定的接口。这样我就可以找到哪些对象具有 IMyClass 实现。我的问题是我无法将其投射到该界面。我不想使用标准 RTTI 和动态转换。

我正在考虑在我的自定义 RTTI 中存储一些指针差异,以便在两个类之间进行转换,但我还没有找到让我满意的实现。

还有其他解决方案吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

请止步禁区 2024-12-05 08:31:13

好吧,如果您坚持不使用 RTTI 语言,您可以像旧的 COM 一样使用:使您的所有类或接口都从以下接口派生:

class IMyCast  // similar to IUnknown
{
public:
    virtual void *CastTo(interfaceId_t id) = 0; //Similar to IUnknown::QueryInterface
};

现在在您的 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
        }
    }
};

然后在用户代码中:

CMyBaseClass *obj;
IMyClass *my = static_cast<IMyClass*>(obj->CastTo(IMyClass_id));

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));
滥情空心 2024-12-05 08:31:13

也许您需要增强您的自定义 RTTI;至少这是我在几乎相同的情况下所做的。我的解决方案没有使用指针差异,而是为必要的(类、接口)对实例化了一个“caster”函数模板。事情是这样的:

  • 所有接口都有一个唯一的 int id。为此,需要从 InterfaceBase 派生 MyInterface。 id 在第一次 MyInterface::GetId() 调用时自动分配。
  • MyClass 的实现者(实现 MyInterface)需要在 .cpp 文件中添加 IMPLMENTS(MyClass, MyInterface) 宏。
  • 该宏实例化一个void* GetInterface(void*)函数,然后在interfaceId -> 中注册一个指向该函数的指针。 GetInterface-函数映射(属于C类)。该函数将其参数转换为 C*,然后将 C* 转换为 I*,最后返回 void*。 (使用 void* 进行黑客攻击是必要的,以便所有这些函数都具有相同的签名,因此它们可以存储在映射中。)
  • 要获取接口,用户需要调用 myObject->GetInterface() 函数,在 CMyBaseClass 中实现。它找到属于this对象的动态类的地图,根据I::GetId()查找适当的caster函数,并通过this调用它。

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文