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

标签 c++ direct2d

这应该很简单。 ID2D1LinearGradientBrush 派生自具有有效 vtable 的 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 接口(interface) __declspec(novtable)作为他们定义的一部分;如果您查看 DX_DECLARE_INTERFACE 的定义,您会发现这里就是这种情况。这意味着基接口(interface)类没有虚表,只有具体实现才有。 RTTI 没有dynamic_cast 正常工作所需的信息。

对于 COM 接口(interface),您应该始终使用 QueryInterface进行动态转换。

关于c++ - 为什么这个 dynamic_cast<T> 不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23688178/

相关文章:

c++ - 在多个文件中使用时包含全局 vector 时出错

c++ - 在屏幕上定位程序位置

c++ - 使用 DirectX11 : Aligning rectangles on a display graph 的 Direct2D 绘图

delphi - FMX Direct 2D 问题

Delphi、Direct2D、TBitmap 和透明度

c++ - 进入EOF后,不能再用cin读取值

c++ - 为什么我们需要 argc 而 argv 的末尾总是有一个空值?

c++ - 哈希表——哈希函数实现

bitmap - 从 IWICBitmapSource、IWICBitmap、IWICBitmapDecoder 获取位图 BitsPerPixel(无论在何处)

xaml - DirectX:- 如何将指针图像数据复制到现有的 D2D1Bitmap?