Jquery中文网 www.jquerycn.cn
Jquery中文网 >  脚本编程  >  C语言  >  正文 C 中超类化和子类化及他们的区别

C 中超类化和子类化及他们的区别

发布时间:2018-09-08   编辑:www.jquerycn.cn
jquery中文网为您提供C 中超类化和子类化及他们的区别等资源,欢迎您收藏本站,我们将为您提供最新的C 中超类化和子类化及他们的区别资源
C 中超类化和子类化是一种编程技术,子类化适合于需要修改少量窗口的属性的情况,超类化适合于需要修改多个窗口的属性的情况。

C 中超类化和子类化

超类化和子类化没有具体的代码,其实是一种编程技巧,在MFC和WTL中可以有不同的实现方法。

窗口子类化:

原理就是改变一个已创建窗口类的窗口过程函数。通过截获已创建窗口的消息,从而实现监视或修改已创建窗口类的行为属性。可以用来改变或者扩展一个已存在的窗口的行为,而不用重新开发。比如要获得那些预定义控件窗口类(按钮控件、编辑控件、列表控件、下 拉列表控件、静态控件和滚动条控件)的功能而又要修改它们的某些行为。

子类化的优点主要体现在以下两个方面:首先,它不需要创建新的窗口类,不需要了解一个窗口的窗口过程。这在原来的窗口函数是由别人编写,而且创建过程不可见的情况下非常有用;其次,子类化比较容易实现,因为所有要做的工作仅仅就是写一个窗口函数。

主要步骤为

    截取该消息,阻止其向原窗口函数发送。
    修改该消息。
    修改完毕以后再向原窗口函数发送。

<pre class="brush:cpp;toolbar:false;">// 保存窗口默认的消息响应函数指针 WNDPROC pSubclassOldEditProc; // 用于替换子类化窗口的消息响应函数 LRESULT CALLBACK JcEditProcSubClass(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {     switch(message)     {     case WM_CHAR:         {             ::MessageBox(hWnd, "WM_CHAR响应", "子类化", MB_OK);             return 0;         }     //使用完后,消息发回原窗体     default: return ::CallWindowProc(pSubclassOldEditProc, hWnd, message, wParam, lParam);      } }   // 对创建好的窗体进行子类化代码 {    // 创建    HWND hEdit = CreateWindowEx(NULL, "EDIT", "SubClass",        WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, 100,120, 128, 16, hWnd, NULL, hInstance, NULL);   //修改窗口属性,改变消息响应函数    pSubclassOldEditProc = (WNDPROC)::SetWindowLong(hEdit, GWL_WNDPROC, (DWORD)JcEditProcSubClass);    // 显示    ShowWindow(hEdit, nCmdShow);    UpdateWindow(hWnd); }</pre>


窗口超类化:

窗口超类化是在窗口类——WNDCLASS或WNDCLASSEX(非MFC类概念)级别进行的改变窗口类特征的。改变已有窗口类的行为属性。

    通过调用 GetClassInfoEx 来获得想要进行超类化操作的窗口类的信息。函数GetClassInfoEx 需要一个指向 WNDCLASSEX 结构的指针,用于当成功返回时填入窗口类的信息。
    按需要修改 WNDCLASSEX 结构的成员,其中有两个成员必须修改:
    hInstance 存放程序的实例句柄
    lpszClassName 指向一个新类名的指针
    不必修改成员 lpfnWndProc,但大多数情况下还是需要的。但要记住如果要使用函数 CallWindowProc 调用老窗口的过程,那就必须保存成员 lpfnWndProc 的原值。
    注册修改完的 WNDCLASSEX 结构,得到一个具有旧窗口类某些特性的新窗口类。
    用新窗口类创建窗。

<pre class="brush:cpp;toolbar:false">WNDPROC pSuperOldEditProc;// 保存窗口默认消息处理函数 // 用于替换的超类化消息响应函数 LRESULT CALLBACK JcEditProcSuper(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {     switch(message)     {     case WM_CHAR:         {             ::MessageBox(hWnd, "WM_CHAR响应", "超类化", MB_OK);             return 0;         }     default: return ::CallWindowProc(pSuperOldEditProc, hWnd, message, wParam, lParam);     } }   // 创建超类化控件代码 {    // 取得原控件信息    WNDCLASSEX myeditClass;    ::GetClassInfoEx(hInstance, "EDIT", &myeditClass);    // 保存原控件默认消息处理函数    pSuperOldEditProc = myeditClass.lpfnWndProc;    // 设置替换的消息处理函数    myeditClass.lpfnWndProc = JcEditProcSuper;    // 指定新的窗口类名字    myeditClass.lpszClassName = "JcilyEdit";    // 设置结构体大小    myeditClass.cbSize = sizeof(WNDCLASSEX);    // 注册新信息    RegisterClassEx(&myeditClass);    // 创建    HWND hEdit = CreateWindowEx(NULL, myeditClass.lpszClassName, "SuperClass",        WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, 100,100, 128, 16, hWnd, NULL, hInstance, NULL);    // 显示    ShowWindow(hEdit, nCmdShow);    UpdateWindow(hWnd); }</pre>


窗口子类化和超类化的区别

(1) 子类化修改窗口过程函数, 超类化修改窗口类(新的窗口类名)
(2) 子类化是在窗口实例级别上的,超类化是在窗口类(WNDCLASS)级别上的。
(3) 超类化可以完成比子类化更复杂的功能,在SDK范畴上,可以认为子类化是超类化的子集。
(4) 子类化只能改变窗口创建后的性质,对于窗口创建期间无能为力(无法截获ON_CREATE 事件),而超类化可以实现;超类化不能用于Windows创建的窗口,子类化可以。
(5) 超类化可以修改包含窗体背景等属性,而子类化不能。


C 超类化和子类化的区别

Q: 我看了WINX开发包中的文档中,你提到了超类,它是什么概念?我平常只听过子类(Subclass)。

A: 子类化(Subclass)是指替换窗口过程(WNDPROC)。
    超类(Superclass)是替换窗口过程(WNDPROC),并且替换ClassName。
   Subclass不太象继承,而像是一种外挂(Hook)行为。
   Superclass则更像继承,因为生成了新的窗口类,并且继承了行为。
   winx中Subclass和Superclass用同一个类实现。都是winx::SubclassWindow。
   其他界面库一般不提供Superclass。
 
Q: 你说其他界面库不提供Superclass?MFC里继承应该属于Superclass吧?

A: 不,MFC中用的是Subclass。

Q: 我怎么感觉不出二者的区别?我是说用法上和结果上。

A: 两者在用法上有异,但获得的结果确实无太大差别。
   我们以Button为例。如果是Subclass,那么用户先要有一个Button,然后Subclass它。
   也就是说Subclass发生在CreateWindow之后。
   如果是Superclass,那么用户CreateWindow的时候直接传入新的窗口类名称,根本就没有Button被生成。
   当然,这要求CreateWindow之前调用过该窗口类的RegisterClass。
   MFC用的是Subclass。因为CButton类通过DDX技术和对话框上的Button关联的。
   也就是说,MFC中是先有了Button,然后由DDX技术Subclass它。
   所以,一般你看不到Subclass流程。
 
Q: 什么情况下需要用SuperClass?
   哦,我明白了,是不是有了SuperClass技术,用户可以很方便的创建自己的Control?
 
A: 对了。不需要从零开始。

Q: 对。感觉多数用户自定义控件还是和系统控件有关系的。

A: 是的。这正是Superclass存在的意义。
   你可以想象一下:在以前,你提供一个控件,你要告诉它,先创建Button,然后调用我的Subclass函数。
   而有了Superclass,现在你只需要告诉它窗口类的名字就可以了。
   因为Superclass隐蔽了你从Button继承这个事实。
 
Q: 对。

A: 之所以winx可以有superclass而其他界面库没有,究其原因,还是与屏蔽“窗口类”这个出发点有关。

Q: 对,对,对。以后自己定义的控件也可以可视化开发。

A: 是的。

Q: 指定一下我们自己的窗口类就可以了。
   WINX这种控件感觉是介于系统控件和ActiveX控件之间的一种控件。

A: 是的。这种控件其实就是Windows系统控件的实现方式。
   只是系统控件不需要你主动注册,Windows已经帮你注册好了。
 
Q: 系统实现这些系统控件不是通过SuperClass吧?它应该是从最一般化的窗口继承而来。

A: 呵呵,当然不是。它们没有什么可以借用的,只好从最基础的winx::Window继承。

Q: 不管是白手起家,还是有点基础,做法都是SuperClass。
   因为winx::Window的基础是DefWindowProc,也是一个窗口过程。
 
A: 可以这么理解。

Q: 是不是可以这样理解,SubClass只是更改了WndProc,而SuperClass还更改了其他窗口属性?

A: 是的。你的理解完全正确,这正是Subclass与Superclass最本质的区别。
   Superclass可以改窗口类(WNDCLASSEX)的任何数据。WINX就是这么实现的。

子类化样例代码:

<pre class="brush:cpp;toolbar:false">// ------------------------------------------------------------------------- // class CMyEdit - 使用子类化(Subclass)技术 class CMyEdit : public winx::Edit<CMyEdit> { public:     VOID OnContextMenu(HWND hWnd, winx::CPoint pt)     {         //禁止了右键菜单...     } }; // ------------------------------------------------------------------------- // CHelloDlg class CHelloDlg : public winx::ModalDialog<CHelloDlg, IDD_HELLO> { public:     BOOL OnInitDialog(HWND hDlg, HWND hWndDefaultFocus)     {         CMyEdit::DoSubclassDlgItem(hDlg, IDC_EDIT1);         return TRUE;     } }; // ------------------------------------------------------------------------- int APIENTRY WinMain(HINSTANCE hInstance,                      HINSTANCE hPrevInstance,                      LPSTR     lpCmdLine,                      int       nCmdShow) {     CHelloDlg dlg;     dlg.DoModal();     return 0; } // -------------------------------------------------------------------------</pre>



超类化样例代码:

<pre class="brush:cpp;toolbar:false">// ------------------------------------------------------------------------- // class CMyEdit2 - 使用超类化(Superclass)技术 class CMyEdit2 : public winx::Edit<CMyEdit2> {     WINX_CLASS("MyEdit"); public:     VOID OnContextMenu(HWND hWnd, winx::CPoint pt)     {         //禁止了右键菜单...     } }; // ------------------------------------------------------------------------- // CHelloDlg class CHelloDlg : public winx::ModalDialog<CHelloDlg, IDD_HELLO> ; // ------------------------------------------------------------------------- int APIENTRY WinMain(HINSTANCE hInstance,                      HINSTANCE hPrevInstance,                      LPSTR     lpCmdLine,                      int       nCmdShow) {     CMyEdit2::RegisterClass();     CHelloDlg dlg;     dlg.DoModal();     return 0; }</pre>


您可能感兴趣的文章:
C 中超类化和子类化及他们的区别
Laravel 深入理解控制反转(IoC)和依赖注入(DI)
Asp.net 页面导航的几种方法与比较
ASP.NET四种页面导航方式的比较与选择
详解C#泛型及其特点
photoshop化妆品瓶子类淘宝美工教程分享
C#只读字段和常量的区别 静态构造函数的例子
C#3.0 匿名类型介绍
超详细的C 指针介绍及实例教程
mysql性能优化之sql优化

[关闭]