代码之家  ›  专栏  ›  技术社区  ›  Matthew Iselin

将派生类实例作为空隙*传递给C++中的一般回调

  •  1
  • Matthew Iselin  · 技术社区  · 16 年前

    这是一个有点复杂的问题,所以我会尽我所能解释到底发生了什么。如果我错过了什么,请告诉我以便我澄清。

    我们有一个回调系统,其中一个模块或应用程序提供一个“服务”,客户机可以使用该服务执行操作(基本上是一个非常基本的IPC)。为了将来的参考,假设我们有一些这样的定义:

    typedef int (*callback)(void*); // This is NOT in our code, but makes explaining easier.
    
    installCallback(string serviceName, callback cb); // Really handled by a proper management system
    
    sendMessage(string serviceName, void* arg); // arg = value to pass to callback
    

    对于结构或内建等基本类型,这很好地工作。

    我们有一个类似这样的MI结构:

    Device <- Disk <- MyDiskProvider
    
    class Disk : public virtual Device
    class MyDiskProvider : public Disk
    

    提供程序可以是任何东西,从硬件驱动程序到处理磁盘图像的胶水。关键是类继承磁盘。

    我们有一个“服务”,系统中的所有新磁盘都会通知我们,这就是问题的症结所在:

    void diskHandler(void *p)
    {
        Disk *pDisk = reinterpret_cast<Disk*>(p); // Uh oh!
    
        // Remainder is not important
    }
    
    SomeDiskProvider::initialise()
    {
        // Probe hardware, whatever...
    
        // Tell the disk system we're here!
        sendMessage("disk-handler", reinterpret_cast<void*>(this)); // Uh oh!
    }
    

    问题是,somediskprovider继承了磁盘,但回调处理程序无法接收该类型(因为回调函数指针必须是泛型的)。

    RTTI和模板在这里有帮助吗?

    任何建议都将不胜感激。

    3 回复  |  直到 16 年前
        1
  •  1
  •   Tomek    16 年前

    虽然我不是100%确定,但我认为静态类型从t*转换为void*并返回到原始指针类型t*应该可以工作。正如我所看到的,问题在于reinterpret-cast只更改指针的类型,而不更改其实际值,而static-cast在继承时应调整指针,使其指向对象的开头。

    免责声明: 你在这门语言的黑暗面上,我不能保证它会起作用。

        2
  •  1
  •   R Samuel Klatchko    16 年前

    你的代码看起来有风险。问题是你投了一个 SomeDiskProvider * void * 然后把它扔回 Disk * .

    您应该转换回您所转换的类型。所以你可以先把你的 SomediskProvider(SomediskProvider)* 到A 磁盘* :

    reinterpret_cast<void*>(static_cast<Disk *>(this))
    

    你又回到了 SomediskProvider(SomediskProvider)* :

    SomeDiskProvider *pDisk = reinterpret_cast<SomeDiskProvider*>(p);
    
        3
  •  1
  •   Niall C.    16 年前

    reinterpret_cast<> 如果您要从 some_type * void * 又回来了。但是,您说您正在使用多重继承,在这种情况下 this 在层次结构中的一个类中,值可能与 在另一个班级; dynamic_cast<> 设计用于遍历继承树并给出正确的答案。

    所以,在 SomeDiskProvider 使用两种类型:

    SomeDiskProvider::initialise()
    {
        // Gets the right value for 'this' for the Disk part of SomeDiskProvider.
        Disk *pDisk = dynamic_cast<Disk *>(this);
    
        // OK, since the callback converts it back to Disk *
        sendMessage("disk-handler", reinterpret_cast<void*>(this));
    }
    

    回调与您在问题中显示的完全相同。