将 DWORD_PTR 转换为类,反之亦然,无需 c 样式转换

Xzs*_*f75 1 c++ winapi visual-studio-2015

根据 Herb Sutter 的C++ Coding Standards: 101 Rules, Guidelines, and Best Practices程序员应该避免 c 样式转换:

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

我正在尝试传递指向p_ctrlWinAPI 回调函数的指针,为此我想使用回调函数的 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 );
}
Run Code Online (Sandbox Code Playgroud)

我已经尝试过动态转换,但这给了我错误。reinterpret_cast根本不应该使用(根据 Sutter)。

请问有没有办法使用 C++ 提供的函数进行这些转换?

and*_*abs 5

萨特的建议就是:建议。它们不是硬性规定;它们只是鼓励您编写更安全、更健壮的代码的建议。

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

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

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

所以继续使用那个 C 风格的 cast 或 that reinterpret_cast<>,无论你喜欢哪个。其他强制转换将不起作用,因为您需要将整数解释为指针,而其他强制转换不会让您这样做。

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