为什么不调用虚拟WndProc?

时间:2014-11-16 17:40:58

标签: c++ winapi

这是我到目前为止所做的...即使我实例化一个Window(WindowBase的子类),我也会收到一个错误,即尝试调用纯虚函数。基本上,我的程序试图调用WindowBase :: WndProc而不是Window :: WndProc。

WINDOWBASE.H

#ifndef WINDOWBASE_H_
#define WINDOWBASE_H_

#include <Windows.h>

class WindowBase {
public:
  WindowBase(HINSTANCE hInstance, int nCmdShow);
  ~WindowBase();

  void Show();

protected:
  virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam) = 0;

private:
  static LRESULT CALLBACK WndRouter(HWND hWnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam);

  HWND hWnd;
  int nCmdShow;
};

#endif /* WINDOWBASE_H_ */

WINDOWBASE.CPP

#include <Windows.h>
#include "WindowBase.h"
#include <tchar.h>

WindowBase::WindowBase(HINSTANCE hInstance, int nCmdShow) {

  this->nCmdShow = nCmdShow;

  WNDCLASS wcex;

  //wcex.cbSize = sizeof(WNDCLASSEX);
  wcex.style = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc = WndRouter;
  wcex.cbClsExtra = 0;
  wcex.cbWndExtra = 0;
  wcex.hInstance = hInstance;
  wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
  wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wcex.lpszMenuName = _T("TestMenu");
  wcex.lpszClassName = _T("TestWindow");
  //wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

  if (!RegisterClass(&wcex)) {
    MessageBox(NULL,  
               "Call to RegisterClassEx failed!",
               "Win32 Guided Tour",
               NULL);
  }

  hWnd = CreateWindow(_T("TestWindow"), _T("TestWindow"), WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, NULL, (void*)this);

  if (!hWnd){
      MessageBox(NULL,
                 "Call to CreateWindow failed!",
                 "Win32 Guided Tour",
                 NULL);
  }
}

WindowBase::~WindowBase() {
}

void WindowBase::Show() {
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
}

LRESULT CALLBACK WindowBase::WndRouter(HWND hWnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam) {
  WindowBase* base = NULL;

  if (uMsg == WM_NCCREATE) {
    base = reinterpret_cast<WindowBase*>(((LPCREATESTRUCT)lParam)->lpCreateParams);
    SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)base);
  } else {
    base = reinterpret_cast<WindowBase*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
  }

  if (!base)
    return DefWindowProc(hWnd, uMsg, wParam, lParam);

  return base->WndProc(hWnd, uMsg, wParam, lParam); // GETS TO HERE, BUT TRIES TO
    // CALL WindowBase::WndProc, INSTEAD OF Window::WndProc
}

window.h中

#ifndef WINDOW_H_
#define WINDOW_H_

#include "windowbase.h"

class Window : public WindowBase {
public:
  Window(HINSTANCE hInstance, int nCmdShow);
  ~Window();

protected:
  virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};

#endif /* WINDOW_H_ */

1 个答案:

答案 0 :(得分:5)

如果您在CreateWindow构造函数中调用WindowBase,则会开始从那里接收消息。

如果您创建了Window对象,那么它自己的构造函数必须调用WindowBase构造函数。在此期间,Window对象尚未出现,因此其虚函数尚不可用(它们将引用尚未构造的窗口......)。

你的设计还有许多其他陷阱:想想每个组件的范围和寿命:其中一些在构造之前使用,另一个在需要时被破坏。

将OOP C API(如WIn32)包装成另一种具有&#34; Object&#34;概念的OOP语言(如C ++)并不容易。和&#34;范围&#34;这不符合WIN32的想法。照顾它们,或者你可以轻松地获得看起来有效的鳕鱼,但是在更广泛的环境中使用(更多的窗口而不仅仅是一个)风险表现得不如预期。