本文适用于对MFC比较了解的中级开发人员。
源代码下载:http://download.csdn.net/source/3522785
ATL Background
ATL-style templates
- class CMyWnd : public CWindowImpl<CMyWnd>
- {
- ...
- };
看下面例子:
- template <class T>
- class B1
- {
- public:
- void SayHi()
- {
- // 此处是关键技巧。
- T* pT = static_cast<T*>(this);
- pT->PrintClassName();
- }
- void PrintClassName() { cout << "This is B1"; }
- };
- class D1 : public B1<D1>
- {
- // No overridden functions at all
- };
- class D2 : public B1<D2>
- {
- void PrintClassName() { cout << "This is D2"; }
- };
- int main()
- {
- D1 d1;
- D2 d2;
- d1.SayHi(); // prints "This is B1"
- d2.SayHi(); // prints "This is D2"
- return 0;
- }
static_cast<T*
>(
this)
是关键
技术。它将
B1*
的
this
根据不同的调用转化为
D1*
或
D2*
。由于模板代码是在编译时生成的,只要继承列表编写正确,这种类型转换就是安全的。
(
避免写出
class D3
public
: B1
<D2
>这种形式的代码。编译器是检测不出的。)
第一次调用
SayHi()
时,代码实际是这样的:
- void B1<D1>::SayHi()
- {
- D1* pT = static_cast<D1*>(this);
- pT->PrintClassName();
- }
D1没有重写PrintClassName(),因此去搜索D1的基类。B1有PrintClassName(),因此实际调用B1::PrintClassName()。
- void B1<D2>::SayHi()
- {
- D2* pT = static_cast<D2*>(this);
- pT->PrintClassName();
- }
D2重写了函数PrintClassName(),直接调用此函数。
这种技术的优点:
1) 不需要使用对象的指针
2) 节省内存,因为不需要使用虚函数表
3) 不会因为未初始化的虚函数表导致使用NULL指针
4) 所有函数的调用在编译时确定,因此它们是可以优化的。
ATL Windowing Classes
ATL严格遵守接口-实现分离的原则。
ATL拥有一个定义Window的接口类:CWindow。它仅仅封装了HWND,并且封装了几乎所有的Use32 APIs中以HWND为第一个参数的接口。例如SetWindowText()
和DestroyWindow()
。
CWindow
提供一个共有的成员
m_hWnd
,可以直接处理
HWND
,也提供了一个
operator
HWND(),可以直接是
CWindow
作为需要
HWND
对象的函数参数。
CWindow
不同于
MFC
中的
CWnd
。
CWindow
易于创建的,它不提供像
MFC
中的
HWND
到
CWnd
的对象关系。当
CWindow
对象超出作用域时,它被销毁,但是它关联的实际窗口不会被销毁。因此不需要
detach
你创建的临时的
CWindow
对象。
ATL
还提供了一个
Window
的实现类
CWindowImpl
。它包含了下列处理:窗口注册、窗口子类、消息映射、以及一个基本的
WindowProc().
不想
MFC
中的
CWnd
,所有的东西都在这个类中。
关于对话框的实现,
ATL
提供了两个独立的实现类
CDialogImpl 和 CAxDialogImpl。前者用于普通对话框 ,后者用于ActiveX控件。
Defining a Window Implementation
定义一个非对话框的窗口类,要从CWindowImpl派生。新类中必须包含三件事情:
1) 窗口类定义
2) 消息映射
3) 一个默认的窗体特征,叫做window traits
1、
窗口类定义用宏DECLARE_WND_CLASS
或 DECLARE_WND_CLASS_EX.
二者均定义了一个
ATL
结构
CWndClassInfo
,它封装了
WNDCLASSEX
结构。前者仅仅定义新的窗口类的名字,其他参数用默认值;后者还可以定义窗口风格和背景色。窗口类的名字可以是
NULL
,此时
ATL
会自动生成一个。
- class CMyWindow : public CWindowImpl<CMyWindow>
- {
- public:
- DECLARE_WND_CLASS(_T("My Window Class"))
- };
2、 消息映射,与MFC类似。ATL 消息映射将之扩展为一个Switch语句,选择正确的句柄执行对应的函数。
- class CMyWindow : public CWindowImpl<CMyWindow>
- {
- public:
- DECLARE_WND_CLASS(_T("My Window Class"))
- BEGIN_MSG_MAP(CMyWindow)
- END_MSG_MAP()
- };
3、 定义window traits. 它是一个窗体风格和用于创建窗体的风格的组合。它们将作为模板参数来封装窗体特征类,这样调用者不必困扰于当创建窗口时如何获取正确的窗体风格。