多个vtables,在拨打电话时会以错误的方式结束

时间:2017-11-01 18:05:01

标签: c++ multiple-inheritance diamond-problem

我有以下设置:

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

// IRpCat
public:
    virtual HRESULT Initialize();

..... blah blah .......

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

..... blah blah .......

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

......等等等等..............

最后

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

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

这是问题所在。在实例化类并进行Initialize()调用时,我最终进入了OnDataChange():

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

Initialize()和OnDataChange()都是各自vtable插槽中的第一个函数 - 所以我不明白发生了什么,但我得到的是通过vtable [0]发生的Initialize()调用 - 但不幸的是,我最终在错误的vtable。在预感中,我尝试了以下内容:

通过将第一行设为虚拟,我最终在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 ++)。它绝对与vtable的布局方式有关。 谢谢

1 个答案:

答案 0 :(得分:1)

想出来。问题是对象实例化的方式:

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

首先将指针存储在“void *”中,然后将其转换为“切片”指针 - 因此产生了奇怪的结果。谢谢大家。