为什么这个dynamic_cast<T>不起作用?

Why is this dynamic_cast<T> not working?

本文关键字:gt 不起作用 lt dynamic cast 为什么      更新时间:2023-10-16

这应该非常简单。ID2D1LinearGradientBrush来源于ID2D1Brush和一个有效的变量表。我意识到QueryInterface可以在这里工作,但是我的问题与dynamic_cast有关。

[definition from d2d1.h]
interface DX_DECLARE_INTERFACE("2cd906ab-12e2-11dc-9fed-001143a055f9") 
ID2D1LinearGradientBrush  : public ID2D1Brush
{
    // ....
}

然而,考虑到过于简化的示例函数…

bool ClampToItem(ID2D1Brush *brush, SizeF itemSize)
{
    // As expected, works when a linear gradient brush is the parameter.
    ID2D1LinearGradientBrush *linearGradientBrush = static_cast<ID2D1LinearGradientBrush *>(brush);
    linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
    linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
    return true;
}
bool ClampToItem2(ID2D1Brush *brush, SizeF itemSize)
{
    // this dynamic cast FAILS EVERY TIME with an access violation
    ID2D1LinearGradientBrush *linearGradientBrush = dynamic_cast<ID2D1LinearGradientBrush *>(brush);
    if (!linearGradientBrush)  // <-- never gets here
        return false;
    linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
    linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
    return true;
}

因为我不确定是否将ID2D1LinearGradientBrush作为参数提供,所以我想使用dynamic_cast。我一定错过了一些简单的东西。这些COM对象不包含RTTI信息吗?谢谢你的帮助。

// For clarification, this works as expected
bool ClampToItem3(ID2D1Brush *brush, SizeF itemSize)
{
    ID2D1LinearGradientBrush *linearGradientBrush;
    HRESULT hr = brush->QueryInterface(__uuidof(ID2D1LinearGradientBrush), (void **)&linearGradientBrush);
    if (hr == S_OK)
    {
        linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
        linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
        linearGradientBrush->Release();
        linearGradientBrush = nullptr;
    }
    return true;
}
编辑:

跟踪到动态强制转换(到rtti.cpp):

extern "C" PVOID __CLRCALL_OR_CDECL __RTDynamicCast(
    PVOID inptr,            // Pointer to polymorphic object
    LONG VfDelta,           // Offset of vfptr in object
    PVOID SrcType,          // Static type of object pointed to by inptr
    PVOID TargetType,       // Desired result of cast
    BOOL isReference)       // TRUE if input is reference, FALSE if input is ptr
    throw(...)

被调用,inptr是有效的,vfDelta是0,SrcType和TargetType看起来很棒,isRef表示false。进一步跟踪,内存访问冲突发生在这里:

// Ptr to CompleteObjectLocator should be stored at vfptr[-1]
_RTTICompleteObjectLocator *pCompleteLocator =
    (_RTTICompleteObjectLocator *) ((*((void***)inptr))[-1]);
char *pCompleteObject = (char *)inptr - COL_OFFSET(*pCompleteLocator);

由于*pCompleteLocator被移动到一个无效的位置。

来自Microsoft的标准COM接口使用__declspec(novtable)作为其定义的一部分;如果你看一下DX_DECLARE_INTERFACE的定义,你会发现这就是这种情况。这意味着基接口类没有变量表,只有具体实现才有。RTTI没有dynamic_cast正常工作所需的信息

对于COM接口,您应该始终使用QueryInterface来进行动态强制转换。