【问题标题】:Switch statement use切换语句使用
【发布时间】:2009-04-04 23:25:35
【问题描述】:

我应该使用这种形式的 switch 语句:

  switch(msg)
  {
    case WM_LBUTTONDOWN:
    {
           char szFileName[MAX_PATH];
           HINSTANCE hInstance = GetModuleHandle(NULL);
           GetModuleFileName(hInstance, (LPWCH)szFileName, MAX_PATH);
           MessageBox(hwnd, (LPCWSTR)szFileName, L"This program is:", MB_OK | MB_ICONINFORMATION);
    }
    break;

    case WM_CLOSE:
        DestroyWindow(hwnd);
    break;
    case WM_DESTROY:
        PostQuitMessage(0);
    break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
  }
  return 0;

或者为第一个 case 常量创建一个函数?

【问题讨论】:

  • 不要将 char (szFileName) 转换为 WCHAR(将其传递给 MessageBox)。这会导致坏事发生!
  • 同意@jeff,请将 szFileName 声明为 'WCHAR szFileName[MAX_PATH];'并摆脱这两种类型转换。

标签: c++ c windows winapi


【解决方案1】:

您拥有它的方式没有任何问题,但调用函数可能是更简洁的代码,因此您可以将函数保持在合理的大小。

【讨论】:

  • 他确实有休息时间,但在大括号之外。让人难以阅读。此外,缩进会损害可读性。而可读性是制作函数的另一个好处,前提是他能想出一个好的函数名。
  • 在布赖恩发布他的解决方案后休息。
  • 我倾向于将 break 放在右大括号之后。不知道为什么,也许是作为“无论你做什么,都不要忘记打破”的提醒(对我自己)。
【解决方案2】:

另外,看看message crackers

【讨论】:

  • 或 C++ 等价物:ATL 的 CWindow 类。你窗口的 cpp 文件看起来会很干净。
【解决方案3】:

你打算什么时候处理 20 或 50 条窗口消息?
也许是时候在函数(函数)上创建映射事件并调用它们了?
或者开始使用规则 - 一条消息 = 一个函数调用。


char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, (LPWCH)szFileName, MAX_PATH);
MessageBox(hwnd, (LPCWSTR)szFileName, L"This program is:", MB_OK | MB_ICONINFORMATION);

你能用 convetion (LPCWSTR)szFileName 解释这个奇怪的技巧吗?为什么不使用数组 wchar_t 来代替强制转换? - 长路径( path_length > MAX_PATH / sizeof( wchar_t ) )会有很大的问题

一个建议 - 避免使用一般的转换,特别是 C 风格的转换。

【讨论】:

    【解决方案4】:

    如果您问是否应该将第一种情况的代码转换为函数,那么是的,当然。

    【讨论】:

      【解决方案5】:

      嗯,这取决于您还有多少其他案例。

      这么小的东西,我会说让它成为一个函数是不值得的,但是如果你的 switch 语句包含更多的情况,它只会变得丑陋,特别是如果很多情况下都有这样的多行.把它放到一个函数中会清理它并使你的代码看起来更好。

      【讨论】:

        【解决方案6】:

        我想说的最重要的事情之一就是一致性。如果您为 LBUTTONDOWN 创建一个函数,则为所有内容创建一个函数。这样一来,如果东西坏了,就可以在哪里找到东西。

        与当前主题相关:

        我个人认为 if / else if 模式效果更好,因为它消除了忘记中断的问题:

        if (msg == WM_LBUTTONDOWN) {
            // your code here
            return 0;
        } else if (msg == WM_DESTROY) {
            PostQuitMessage(0);
            return;
        } else if (msg == WM_KEYDOWN) {
            if (wp == VK_F1) {
                DoSomething();
                return;
            }
        }
        return DefWindowProc(hWnd, msg, wp, lp);
        

        这真的取决于你,最终。

        【讨论】:

        • 如果您的案例变大,则开关/案例可以(有时)更有效。我记得当我编写 6510 仿真器时,操作码解码器以 IF 语句开始(我还年轻)。它很慢。使用 case 语句会产生一个跳转表,而且速度更快!
        • Code Complete 的 Steve Mcconnell 测试了这两种方式都是正确的,有时 case 语句更快,有时 if else 构造更快。有时没有区别。所以在出现性能问题之前不要担心,然后再次profile,更改和profile
        【解决方案7】:

        我可能会为每条消息声明一个映射并使用函子:

        typedef std::map<UINT, boost::function<int (HWND, WPARAM, LPARAM) > > messageFuncs_t;
        messageFuncs_t messageFuncs;
        

        然后,当创建窗口类时,只需为每条消息添加一个新函数:

        messageFuncs[WM_LBUTTONDOWN] = &onMouseDownEvent;
        

        ...然后这样实现消息循环:

        messageFuncs_t::iterator fun = messageFuncs.find(msg);
        if(fun != messageFuncs.end())
            return (*fun)(hWnd, wparam, lparam);
        else
            return DefWindowProc(hWnd, msg, wp, lp);
        

        ... 或任何有效的方法。然后很容易添加新消息,并将每个消息的工作委托给一个函数。干净、简洁、有意义。

        【讨论】:

        • 如果您要费心查找消息,则没有理由进行第二次查找 (operator[]) 来调用它。此外,您正在使用带有 boost::function 的函数语法指针,这是不必要的(即使使用实际的函数指针),而且我很确定它不会起作用。
        • 你是对的。我很快就把它放在一起,没有费心查阅文档。我会解决的。
        【解决方案8】:

        您在第一个 case 上缺少一个 break。除此之外,我肯定会将该代码放在单独的函数中。

        【讨论】:

        • 中断在右括号之后。
        【解决方案9】:

        这很好,但我通常不喜欢混合样式和缩进。如果我需要将一个案例括起来,我可能会将它们全部括起来并保持缩进一致。

        bb 也是对的,在这种情况下你应该使用 wchar_t 数组而不是 char。

        【讨论】:

          【解决方案10】:

          我正在编写相当多的 Win32 消息破解程序,例如这些开关。

          我的经验法则是:将行为连接到开关中,将行为连接到单独的函数中。这通常意味着开关包含是否应处理此命令的决定(例如,测试发送者 ID)和“美化”参数。

          所以在这种特殊情况下,一个单独的函数。

          最初的动机是我经常在其他情况下触发行为(例如“当没有指定文件名并且使用设置为full的moon参数调用对话框时,立即显示另存为对话框")。

          【讨论】:

            猜你喜欢
            • 2014-08-24
            • 1970-01-01
            • 1970-01-01
            • 2011-06-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多