#include <windows.h> LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char szAppName[] = "Hello world"; HWND hWnd; MSG msg; WNDCLASS wnd; wnd.cbClsExtra = NULL; wnd.cbWndExtra = NULL; wnd.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wnd.hCursor = LoadCursor(NULL, IDC_ARROW); wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); wnd.hInstance = hInstance; wnd.lpfnWndProc = WndProc; wnd.lpszClassName = szAppName; wnd.lpszMenuName = NULL; wnd.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClass(&wnd)) { MessageBox(NULL, "Can not register window class", "Error", MB_OK | MB_ICONINFORMATION); return -1; } hWnd = CreateWindow(szAppName, "Hello world", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; RECT rect; switch (uMsg) { case WM_PAINT: hDC = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rect); DrawText(hDC, "Hello world", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } |
class ZWindow { public: HWND m_hWnd; ZWindow(HWND hWnd = 0) : m_hWnd(hWnd) { } inline void Attach(HWND hWnd) { m_hWnd = hWnd; } inline BOOL ShowWindow(int nCmdShow) { return ::ShowWindow(m_hWnd, nCmdShow); } inline BOOL UpdateWindow() { return ::UpdateWindow(m_hWnd); } }; |
class ZWindow { public: HWND m_hWnd; ZWindow(HWND hWnd = 0) : m_hWnd(hWnd) { } inline void Attach(HWND hWnd) { m_hWnd = hWnd; } inline BOOL ShowWindow(int nCmdShow) { return ::ShowWindow(m_hWnd, nCmdShow); } inline BOOL UpdateWindow() { return ::UpdateWindow(m_hWnd); } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); break; } return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } }; |
ZWindow zwnd; WNDCLASS wnd; wnd.lpfnWndProc = wnd.WndProc; |
cannot convert from ''long (__stdcall ZWindow::*)(struct HWND__ *, unsigned int,unsigned int,long)'' to ''long (__stdcall *)(struct HWND__ *, unsigned int, unsigned int,long) |
原因是你不能将成员函数作为回调函数来传递。为什么呢?因为在成员函数的情况下,编译器会自动传给成员函数一个参数,这个参数是指向这个类的指针,或者换句话说是this指针。所以这就意味着当你在成员函数中传递了n个参数的话,那么编译器会传递n+1个参数,并且那个附加的参数就是this指针。这条错误消息就表明编译器不能将成员函数转换为全局函数。
那么,如果我们想将成员函数作为回调函数的话,应该怎么办呢?如果我们告诉编译器,不传递第一个this指针参数的话,那么我们就可以将成员函数作为回调函数了。在C++中,如果我们将成员函数声明为static的话,那么编译器就不会传递this指针了。这就是static和非static成员函数实质上的不同。
所以,我们可以把ZWindow类中的WndProc声明为static成员函数。这一技术也可以用在多线程的情况下,比如当你想要使用成员函数作为一个线程函数的时候,你就可以将一个static成员函数作为线程函数。
下面就是使用了ZWindow类的更新程序。
程序67.
#include <windows.h> class ZWindow { public: HWND m_hWnd; ZWindow(HWND hWnd = 0) : m_hWnd(hWnd) { } inline void Attach(HWND hWnd) { m_hWnd = hWnd; } inline BOOL ShowWindow(int nCmdShow) { return ::ShowWindow(m_hWnd, nCmdShow); } inline BOOL UpdateWindow() { return ::UpdateWindow(m_hWnd); } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); break; } return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } }; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char szAppName[] = "Hello world"; HWND hWnd; MSG msg; WNDCLASS wnd; ZWindow zwnd; wnd.cbClsExtra = NULL; wnd.cbWndExtra = NULL; wnd.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wnd.hCursor = LoadCursor(NULL, IDC_ARROW); wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); wnd.hInstance = hInstance; wnd.lpfnWndProc = ZWindow::WndProc; wnd.lpszClassName = szAppName; wnd.lpszMenuName = NULL; wnd.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClass(&wnd)) { MessageBox(NULL, "Can not register window class", "Error", MB_OK | MB_ICONINFORMATION); return -1; } hWnd = CreateWindow(szAppName, "Hello world", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); zwnd.Attach(hWnd); zwnd.ShowWindow(nCmdShow); zwnd.UpdateWindow(); while (GetMessage(&msg, NULL, 0, 0)) { DispatchMessage(&msg); } return msg.wParam; } |
switch (uMsg) { case WM_PAINT: hDC = ::BeginPaint(hWnd, &ps); ::GetClientRect(hWnd, &rect); ::DrawText(hDC, "Hello world", -1, &rect, DT_CENTER | DT_VCENTER DT_SINGLELINE); ::EndPaint(hWnd, &ps); break; case WM_DESTROY: ::PostQuitMessage(0); break; } |
#include <iostream> using namespace std; class C { public: void NonStaticFunc() { cout << "NonStaticFun" << endl; } static void StaticFun(C* pC) { cout << "StaticFun" << endl; pC->NonStaticFunc(); } }; int main() { C objC; C::StaticFun(&objC); return 0; } |
StaticFun NonStaticFun |
#include <windows.h> class ZWindow; ZWindow* g_pWnd = NULL; class ZWindow { public: HWND m_hWnd; ZWindow(HWND hWnd = 0) : m_hWnd(hWnd) { } inline void Attach(HWND hWnd) { m_hWnd = hWnd; } inline BOOL ShowWindow(int nCmdShow) { return ::ShowWindow(m_hWnd, nCmdShow); } inline BOOL UpdateWindow() { return ::UpdateWindow(m_hWnd); } inline HDC BeginPaint(LPPAINTSTRUCT ps) { return ::BeginPaint(m_hWnd, ps); } inline BOOL EndPaint(LPPAINTSTRUCT ps) { return ::EndPaint(m_hWnd, ps); } inline BOOL GetClientRect(LPRECT rect) { return ::GetClientRect(m_hWnd, rect); } BOOL Create(LPCTSTR szClassName, LPCTSTR szTitle, HINSTANCE hInstance, HWND hWndParent = 0, DWORD dwStyle = WS_OVERLAPPEDWINDOW, DWORD dwExStyle = 0, HMENU hMenu = 0) { m_hWnd = ::CreateWindowEx(dwExStyle, szClassName, szTitle, dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWndParent, hMenu, hInstance, NULL); return m_hWnd != NULL; } static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ZWindow* pThis = g_pWnd; HDC hDC; PAINTSTRUCT ps; RECT rect; switch (uMsg) { case WM_PAINT: hDC = pThis->BeginPaint(&ps); pThis->GetClientRect(&rect); ::DrawText(hDC, "Hello world", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); pThis->EndPaint(&ps); break; case WM_DESTROY: ::PostQuitMessage(0); break; } return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } }; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char szAppName[] = "Hello world"; MSG msg; WNDCLASS wnd; ZWindow zwnd; wnd.cbClsExtra = NULL; wnd.cbWndExtra = NULL; wnd.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wnd.hCursor = LoadCursor(NULL, IDC_ARROW); wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); wnd.hInstance = hInstance; wnd.lpfnWndProc = zwnd.WndProc; wnd.lpszClassName = szAppName; wnd.lpszMenuName = NULL; wnd.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClass(&wnd)) { MessageBox(NULL, "Can not register window class", "Error", MB_OK | MB_ICONINFORMATION); return -1; } g_pWnd = &zwnd; zwnd.Create(szAppName, "Hell world", hInstance); zwnd.ShowWindow(nCmdShow); zwnd.UpdateWindow(); while (GetMessage(&msg, NULL, 0, 0)) { DispatchMessage(&msg); } return msg.wParam; } |
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ZWindow* pThis = g_pWnd; switch (uMsg) { case WM_CREATE: pThis->OnCreate(wParam, lParam); break; case WM_PAINT: pThis->OnPaint(wParam, lParam); break; case WM_DESTROY: ::PostQuitMessage(0); break; } return ::DefWindowProc(hWnd, uMsg, wParam, lParam); } |