将派生的类实例作为void*传递给C ++中的通用回调
-
30-09-2019 - |
题
这是一个涉及的问题,因此我将尽力解释发生了什么。如果我想念什么,请告诉我,以便我可以澄清。
我们有一个回调系统,一方面,模块或应用程序提供了“服务”,客户可以使用此服务执行操作(基本上是非常基本的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!
}
问题是,有一天会继承磁盘,但是回调处理程序无法接收该类型(因为回调功能指针必须是通用的)。
RTTI和模板在这里可以提供帮助吗?
任何建议将不胜感激。
解决方案
虽然我不是100%确定我认为static_cast从t*到void*,然后回到原始的指针type t*应该起作用。如我所见,问题是reinterpret_cast仅更改指针的类型,而无需更改其实际值,并且在继承时static_cast应该调整指针,以便指向对象的开始。
免责声明: 您在这里语言的阴暗面,我不能保证它会完全有效。
其他提示
您的代码看起来风险。问题是你投了 SomeDiskProvider *
到 void *
然后将其归还给 Disk *
.
您应该归还给您铸造的确切类型。所以你可以先投下 SomeDiskProvider *
到 Disk *
:
reinterpret_cast<void*>(static_cast<Disk *>(this))
或者 你把 SomeDiskProvider *
:
SomeDiskProvider *pDisk = reinterpret_cast<SomeDiskProvider*>(p);
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));
}
回调与您在问题中显示的完全一样。