在没有c风格强制转换的情况下,将DWORD_PTR强制转换为class,反之亦然

Cast DWORD_PTR to class and vice versa without c-style cast

本文关键字:转换 DWORD 反之亦然 class PTR 风格 情况下      更新时间:2023-10-16

根据Herb Sutter的c++编码标准:101规则、指南和最佳实践,程序员应该避免C风格的强制转换:

c风格的强制转换根据上下文具有不同的(通常是危险的)语义,所有这些都隐藏在单个语法之后。用c++风格的强制转换替换C风格的强制转换有助于防止意外错误

我试图将指针p_ctrl传递给WinAPI回调函数,为此我想使用回调函数的DWORD_PTR参数(下面的示例正在工作,但包含c风格的类型转换,其中注释):

WndCtrls* WndCtrls::Button ( WndCtrls* const p_ctrl, HWND hwnd, RECT const &rc )
{
    p_ctrl->ctrl = CreateWindowEx (
        0,
        L"BUTTON",
        p_ctrl->w_classNameButton.c_str (),
        WS_VISIBLE | WS_CHILD | BS_OWNERDRAW,
        rc.left,
        rc.top,
        rc.right,
        rc.bottom,
        hwnd,
        0,
        (HINSTANCE)GetWindowLongPtr ( hwnd, GWL_HINSTANCE ), // Problematic C-style cast for which I already know workaround
        p_ctrl
    );
    SetWindowSubclass ( p_ctrl->ctrl, WndCtrls::CtrlProc, 0, (DWORD_PTR)p_ctrl ) ) // C-style cast
    return p_ctrl;
}
LRESULT CALLBACK WndCtrls::CtrlProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
    WndCtrls* const p_ctrl = (WndCtrls*)dwRefData; // Problematic C-style cast
    switch ( message )
    {
        ...
    }
    return DefSubclassProc ( hwnd, message, wParam, lParam );
}

我已经尝试了动态强制转换,但这给了我错误。根据Sutter的说法,根本不应该使用reinterpret_cast

请有一种方法来做这些转换使用c++提供的函数?

Sutter的建议只是建议。它们不是硬性规定;它们只是鼓励你编写更安全、更健壮的代码的建议。

这是advice不起作用的情况之一。

在许多地方,Windows API需要能够传递可能是也可能不是指针的数据。因此,它使用指针大小的整数,使用c风格的强制转换(记住Windows API主要是基于c的)将整数转换为指针。这个安全的,因为文档要求它是:如果你给Windows一个垃圾指针值,你就违反了该函数的规则!

指针大小的整数的标准C/c++名称是intptr_t(有符号)和uintptr_t(无符号)。然而,Windows早于C99和c++ 11(当它们被引入时),所以它使用自己的名称:LONG_PTR(有符号的)和DWORD_PTRULONG_PTR(无符号的)。此外,WPARAMLPARAMLRESULT也是指针大小的,因为窗口消息经常需要处理指针。

所以继续使用c风格的强制转换或者reinterpret_cast<>,你喜欢哪个就用哪个。其他类型转换不能工作,因为您需要将整数解释为指针,而其他类型转换不允许您这样做。

无论如何你可能需要这些,因为有其他地方,因为Windows API不仅需要在C中,而且还需要从其他语言中可用,子类化被作为派生结构的第一个元素的结构对象所取代。这在WM_NOTIFY消息中最为明显,其中所有可能的通知结构都对NMHDR执行此操作。请记住这一点