在软件开发里,大家一直对着这个问题是执着的,那是“复用”。总想自己写出来的代码,可以适应性很强,到那里都可以落地生根。因此,面向对象的语言就层出不穷,每个都坚称可以最大地复用代码。在面向对象里, C ++是非常强大的。下面就来用 C ++把上面介绍的程序封装起来,这样可以复用,或者说条理更加清晰。 #001 #002 int APIENTRY _tWinMain(HINSTANCE hInstance, #003 HINSTANCE hPrevInstance, #004 LPTSTR lpCmdLine, #005 int nCmdShow) #006 { #007 UNREFERENCED_PARAMETER(hPrevInstance); #008 UNREFERENCED_PARAMETER(lpCmdLine); #009 #010 CCaiWin caiWin; #011 #012 caiWin.MyRegisterClass(hInstance); #013 if (!caiWin.InitInstance(hInstance,nCmdShow)) #014 { #015 return 0; #016 } #017 #018 return caiWin.RunMessage(); #019 } 这段代码跟前面介绍的调用,就是不一样了。 第 10 行创建了一个 CCaiWin 的对象 caiWin 。 第 12 行调用对象 CCaiWin 里的注册函数 MyRegisterClass 来注册一个窗口。 第 13 行就是初始化一个窗口的创建。 第 18 行就是调用对象 caiWin 的消息处理函数 RunMessage 。 这样就制定了一个基本应用的框架,可以任意修改对象里的内容,都不会影响这个函数里的调用,也就是说,只要不改那几个函数就可以永远不用修改 WinMain 函数里的内容了。 接着下来,再来看看类 CCaiWin 是怎么样编写的。它的类定义如下: #001 #include <string> #002 #003 // #004 // 封装一个窗口类。 #005 // 蔡军生 2007/07/27 #006 // #007 class CCaiWin #008 { #009 public: #010 CCaiWin(void); #011 virtual ~CCaiWin(void); #012 #013 ATOM MyRegisterClass(HINSTANCE hInstance); #014 bool InitInstance(HINSTANCE hInstance, int nCmdShow); #015 int RunMessage(void); #016 HINSTANCE GetAppInstance(void) #017 { #018 return m_hInstance; #019 } #020 protected: #021 static LRESULT CALLBACK WndProc(HWND hWnd, #022 UINT message, WPARAM wParam, LPARAM lParam); #023 static INT_PTR CALLBACK About(HWND hDlg, #024 UINT message, WPARAM wParam, LPARAM lParam); #025 protected: #026 HINSTANCE m_hInstance; #027 HWND m_hWnd; #028 #029 std::wstring m_strWindowClass; #030 std::wstring m_strTitle; #031 }; 第 7 行定义类 CCaiWin 。 第 13 行是声明 MyRegisterClass 注册函数。 第 14 行是声明 InitInstance 初始化窗口函数。 第 15 行是声明 RunMessage 消息处理函数。 第 16 行是定义 GetAppInstance 函数获取应用程序句柄。 第 21 行是声明窗口的消息处理函数。它是静态成员函数,所以它有全局的地址,因此它是没有 this 指针的,不能直接地访问这个类里的成员变量。需要使用其它方法给它传递。 第 23 行是关于对话框的消息处理函数。 第 26 行是保存应用程序句柄。 第 27 行是保存主窗口的句柄。 第 29 行是保存注册窗口名称。 第 30 行是保存窗口显示的标题。 下面再来仔细地查看类的实现文件。 #001 // #002 // 函数 : InitInstance(HINSTANCE, int) #003 // #004 // 目的 : 保存程序实例句柄,并创建窗口显示。 #005 // #006 // 蔡军生 2007/07/27 QQ:9073204 #007 // #008 bool CCaiWin::InitInstance(HINSTANCE hInstance, int nCmdShow) #009 { #010 // #011 m_hInstance = hInstance; #012 #013 m_hWnd = CreateWindow(m_strWindowClass.c_str(), m_strTitle.c_str(), #014 WS_OVERLAPPEDWINDOW, #015 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); #016 #017 if (!m_hWnd) #018 { #019 return false; #020 } #021 #022 // 保存类的指针到窗口 GWL_USERDATA 字段, #023 // 以便消息函数里可以获取类指针。 #024 SetWindowLongPtr(m_hWnd, GWL_USERDATA,(LONG)(LONG_PTR)this); #025 #026 ShowWindow(m_hWnd, nCmdShow); #027 UpdateWindow(m_hWnd); #028 #029 return true; #030 } 这里创建窗口,跟以前创建窗口,只有一个地方不一样,那就是在第 24 行里调用 SetWindowLongPtr 函数保存对象指针到窗口用户自定义数据里,这样做就是让后面的静态成员函数 WndProc 可以访问类成员。如下: #001 // #002 // 函数 : WndProc(HWND, UINT, WPARAM, LPARAM) #003 // #004 // 目的 : 处理主窗口的消息 . #005 // #006 // 蔡军生 2007/07/27 QQ:9073204 #007 // #008 LRESULT CALLBACK CCaiWin::WndProc(HWND hWnd, UINT message, #009 #010 WPARAM wParam, LPARAM lParam) #011 { #012 // 获取窗口对应的类指针。 #013 LONG_PTR plptrWin = GetWindowLongPtr(hWnd,GWLP_USERDATA); #014 if (plptrWin == NULL) #015 { #016 return DefWindowProc(hWnd, message, wParam, lParam); #017 } #018 #019 // #020 CCaiWin* pWin = reinterpret_cast<CCaiWin*>(plptrWin); #021 #022 int wmId, wmEvent; #023 PAINTSTRUCT ps; #024 HDC hdc; #025 #026 switch (message) #027 { #028 case WM_COMMAND: #029 wmId = LOWORD(wParam); #030 wmEvent = HIWORD(wParam); #031 // 菜单选项命令响应 : #032 switch (wmId) #033 { #034 case IDM_ABOUT: #035 DialogBox(pWin->GetAppInstance(), MAKEINTRESOURCE(IDD_ABOUTBOX), #036 hWnd, CCaiWin::About); #037 break; #038 case IDM_EXIT: #039 DestroyWindow(hWnd); #040 break; #041 default: #042 return DefWindowProc(hWnd, message, wParam, lParam); #043 } #044 break; #045 case WM_PAINT: #046 { #047 hdc = BeginPaint(hWnd, &ps); #048 // #049 std::wstring strShow(_T("C++ 窗口类的实现 ,2007-07-27")); #050 TextOut(hdc,10,10,strShow.c_str(),(int)strShow.length()); #051 #052 // #053 EndPaint(hWnd, &ps); #054 } #055 break; #056 case WM_DESTROY: #057 // 设置窗口类指针为空。 #058 SetWindowLongPtr(hWnd, GWL_USERDATA,NULL); #059 #060 PostQuitMessage(0); #061 break; #062 default: #063 return DefWindowProc(hWnd, message, wParam, lParam); #064 } #065 return 0; #066 } 上面第 13 行就是获取窗口里保存的类对象指针,然后再作类型转换为窗口 CCaiWin 的指针,这样就可以使用类的成员了,比如在第 35 行里的调用 pWin->GetAppInstance() 。 其实在封装静态成员函数这里,就有三种方法传递类指针,上面介绍这种是最简单的。一种是 MFC 里使用的,它是采用一个窗口和类指针映射数组来实现的。一种是 WTL 里使用叫做 THUNK 代码实现窗口与静态函数的关联。像上面这种方法,在游戏 Second Life 的源程序就使用它,如果是一般的应用程序,而不是大框架,使用这种简单的方法,就是最好的。 函数 GetWindowLongPtr 和 SetWindowLongPtr 声明如下: WINUSERAPI LONG WINAPI GetWindowLongA( __in HWND hWnd, __in int nIndex); WINUSERAPI LONG WINAPI GetWindowLongW( __in HWND hWnd, __in int nIndex); #ifdef UNICODE #define GetWindowLong GetWindowLongW #else #define GetWindowLong GetWindowLongA #endif // !UNICODE WINUSERAPI LONG WINAPI SetWindowLongA( __in HWND hWnd, __in int nIndex, __in LONG dwNewLong); WINUSERAPI LONG WINAPI SetWindowLongW( __in HWND hWnd, __in int nIndex, __in LONG dwNewLong); #ifdef UNICODE #define SetWindowLong SetWindowLongW #else #define SetWindowLong SetWindowLongA #endif // !UNICODE #define GetWindowLongPtrA GetWindowLongA #define GetWindowLongPtrW GetWindowLongW #ifdef UNICODE #define GetWindowLongPtr GetWindowLongPtrW #else #define GetWindowLongPtr GetWindowLongPtrA #endif // !UNICODE #define SetWindowLongPtrA SetWindowLongA #define SetWindowLongPtrW SetWindowLongW #ifdef UNICODE #define SetWindowLongPtr SetWindowLongPtrW #else #define SetWindowLongPtr SetWindowLongPtrA #endif // !UNICODE hWnd 是窗口句柄。 nIndex 是访问窗口对象数据的索引值。比如像 GWLP_USERDATA 、 GWLP_WNDPROC 。 dwNewLong 是设置的新值。
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow