超類與子類(Superclass & Subclass)
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就是這麼實現的。
附錄
範例參見:
tutorials/winx/step004-user-ctrl/2.superclass/hello.cpp
子類化範例代碼:
// -------------------------------------------------------------------------
// 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;
}
// -------------------------------------------------------------------------
超類化範例代碼:
// -------------------------------------------------------------------------
// 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;
}
// -------------------------------------------------------------------------