这是一个涉及的问题,所以我会尽我所能来解释发生了什么。如果我错过了什么,请告诉我,我可以澄清一下。
我们有一个回调系统,一方面模块或应用程序提供“服务”,客户端可以使用此服务执行操作(基本上是一个非常基本的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和模板可以在这里提供帮助吗?
任何建议都将不胜感激。
答案 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));
}
回调与您在问题中显示的完全一样。