多个vtable,在打电话时出现错误

multiple vtables, ending up in the wrong one when making a call

本文关键字:错误 打电话 vtable 多个      更新时间:2023-10-16

我有以下设置:

class CRpCat : 
public CQueryDataBase,
public IRpCat 
{
public:
CRpCat();
virtual ~CRpCat();
// IRpCat
public:
virtual HRESULT Initialize();

等等。。。。。。。

class CQueryDataBase : public CQueryNotify
{
// this has virtual functions, all concrete
virtual void OnDataChange(ULONG nRow, DBREASON eReason);

等等。。。。。。。

class CQueryNotify 
{
public:
// abstract signatures
virtual void OnDataChange(ULONG nRow, DBREASON eReason) = 0;

等等。。。。。。。。。。。。。。

最后是

class IRpCat
{
public:
virtual HRESULT Initialize() = 0;

所以,我有一个派生自两个类的类,到处都是虚拟函数。派生自的类不在一个父类下——这不是钻石问题(尽管可能与其相关)

问题来了。当实例化类并调用Initialize()时,我最终会使用OnDataChange():

IRpCat *pCat = GetInstance()->GetRpCat();
pCat->Initialize();

Initialize()和OnDataChange()都是各自vtable槽中的第一个函数——所以我不明白发生了什么,但我知道Initialize(。凭直觉,我尝试了以下方法:

通过使第一行成为虚拟行,我最终正确地进入Initialize()

class CRpCat : 
public virtual CQueryDataBase,
public IRpCat 
{

通过将第二行设为虚拟行,我错误地进入了OnDataChange()

class CRpCat : 
public CQueryDataBase,
public virtual IRpCat 
{

通过使这两行都是虚拟的,它在Initialize()调用时抛出异常

class CRpCat : 
public virtual CQueryDataBase,
public virtual IRpCat 
{

那么,有人能解释一下发生了什么吗?(顺便说一下,这是Visual Studio C++)。这肯定与vtables的布局方式有关。谢谢

想明白了。问题在于对象的实例化方式:

void * p = new CRpCat();
IRpCat * p2 = static_cast<IRpCat *>(p);
p2->Initialize();

先将指针存储在"void*"中,然后进行强制转换,这是对指针的"切片"——因此会产生奇怪的结果。谢谢大家。