将派生类实例作为void *传递给C ++中的泛型回调

时间:2010-04-21 04:23:19

标签: c++ callback multiple-inheritance rtti derived-class

这是一个涉及的问题,所以我会尽我所能来解释发生了什么。如果我错过了什么,请告诉我,我可以澄清一下。

我们有一个回调系统,一方面模块或应用程序提供“服务”,客户端可以使用此服务执行操作(基本上是一个非常基本的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继承了Disk,但回调处理程序无法接收该类型(因为回调函数指针必须是通用的)。

RTTI和模板可以在这里提供帮助吗?

任何建议都将不胜感激。

3 个答案:

答案 0 :(得分:1)

虽然我不是100%肯定我认为从T *到void *的static_cast和返回到原始指针类型T *应该有效。我认为问题是reinterpret_cast只改变了指针的类型而没有改变它的实际值,而在继承的情况下,static_cast应该调整一个指针,使它指向对象的开头。

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

答案 1 :(得分:1)

您的代码看起来很危险。问题是您将SomeDiskProvider *转换为void *,然后将其转发回Disk *

你应该回到你投射的确切类型。因此,您可以先将SomeDiskProvider *转换为Disk *

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

您回放到SomeDiskProvider *

SomeDiskProvider *pDisk = reinterpret_cast<SomeDiskProvider*>(p);

答案 2 :(得分:1)

如果您从reinterpret_cast<>转换为some_type *并再次返回,则

void *即可。但是,您说您正在使用多重继承,在这种情况下,层次结构中某个类中的this可能与另一个类中的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));
}

回调与您在问题中显示的完全一样。