To explain how this works, let's look at each call to SayHi(). In the first call, the specialization B1<D1> is being used, so the SayHi() code expands to:
它是怎么工作的呢?让我们看看每一次的SayHi()的调用。第一次,使用特殊的B1<D1>,SayHi()的代码展开如下:
void B1<D1>::SayHi()
{
D1* pT = static_cast<D1*>(this);
pT->PrintClassName();
}
Since D1 does not override PrintClassName(), D1's base classes are searched. B1 has a PrintClassName() method, so that is the one called.
由于D1没有重载PrintClassName(),D1的基类被找到,B1有一个PrintClassName()的方法,所有有了那次调用。
Now, take the second call to SayHi(). This time, it's using the specialization B1<D2>, and SayHi() expands to:
现在,再来看第二次SayHi()调用。这次,它使用B1<D2>,SayHi()展开如下:
void B1<D2>::SayHi()
{
D2* pT = static_cast<D2*>(this);
pT->PrintClassName();
}
This time, D2 does contain a PrintClassName() method, so that is the one that gets called.
这次D2包含了PrintClassName()函数,所以会直接调用这个函数。
The benefits of this technique are:
这个技巧的好处是:
· It doesn't require using pointers to objects.
· It saves memory because there is no need for vtbls.
· It's impossible to call a virtual function through a null pointer at runtime because of an uninitialized vtbl.
· All function calls are resolved at compile time, so they can be optimized.
· 它不需要用对象指针
· 它节约了vtbls所需的内存
· 在运行时不可能发生因为没有初始化vtbl而通过一个空指针调用虚函数。
· 所有的函数调用在编译时被处理并优化。
While the saving of a vtbl doesn't seem significant in this example (it would only be 4 bytes), think of the case where there are 15 base classes, some of those containing 20 methods, and thes savings adds up.
在这个例子中节约vtbl的内存空间似乎不是很有意义,因为它只需要4个字节,试想如果现在处理的是15个基类,每个基类都有20个方法,那会节约多少内存阿!
ATL Windowing Classes
OK, enough background! Time to dive into ATL. ATL is designed with a strict interface/implementation division, and that's evident in the windowing classes. This is similar to COM, where interface definitions are completely separate from an implementation (or possibly several implementations).
好的,有了足够的背景知识,下面我们将深入ATL。ATL原意是为了实现一种严格的接口/实现分离的机制,这在它的窗体类中是很明显的事情。这有点像COM,COM的接口定义就是完全和实现(可能是一个实现)分离的。
ATL has one class that defines the "interface" for a window, that is, what can be done with a window. This class is called CWindow. It is nothing more than a wrapper around an HWND, and it provides almost all of the User APIs that take an HWND as the first parameter, such as SetWindowText() and DestroyWindow(). CWindow has a public member m_hWnd that you can access if you need the raw HWND. CWindow also has a operator HWND method, so you can pass a CWindow object to a function that takes an HWND. There is no equivalent to CWnd::GetSafeHwnd().
ATL有一个定义了窗体接口的类CWindow。它是一个HWND句柄的封装,它几乎提供了用户API中所有的第一个参数是HWND的函数,例如SetWindowText()和DestroyWindow()。CWindow有一个公共的成员m_hWnd,如果你希望使用HWND句柄时,可以使用它。CWindow中没有与CWnd::GetSafeHwnd()等价的函数。
(如果你看过MFC的代码的话,CWnd::GetSafeHwnd()是在ASSERT(m_hWnd)后,返回了m_hWnd,使用CWindow::m_hWnd时,需要注意句柄是否为空,当然正常情况下为空的情况并不多见。 --- 蜗牛手记)
CWindow is very different from MFC's CWnd. CWindow objects are inexpensive to create, since there is only one data member, and there is no equivalent to the object maps that MFC keeps internally to map HWNDs to CWnd objects. Also unlike CWnd, when a CWindow object goes out of scope, the associated window is not destroyed. This means you don't have to remember to detach any temp CWindow objects you might create.
CWindow与MFC的CWnd有很多的不同。CWindow对象是一个很轻巧的对象,因为它只有一个数据成员,它不像CWnd那样保存着子类功能的函数映射。也不像CWnd那样在注销的时候自动销毁所连接的窗体(即HWND),这就意味着你不得不自己detach所有你生成的临时CWindow对象。
The ATL class that has the implementation of a window is CWindowImpl. CWindowImpl contains the code for such things as window class registration, window subclassing, message maps, and a basic WindowProc(). Again, this is unlike MFC where everything is in one class, CWnd.
ATL还有一个窗体的实现类CWindowImpl。CWindowImpl包含像窗体注册,子类化,消息映射,WindowProc()函数这样功能的代码。要说明的是,这一点不像MFC,MFC中的每件东西都在一个类中,CWnd。
There are also two separate classes that contain the implementation of a dialog box, CDialogImpl and CAxDialogImpl. CDialogImpl is used for plain dialogs, while CAxDialogImpl is used for dialogs that host ActiveX controls.
有2个单独的类包含对话框的实现,CDialogImpl和CAxDialogImpl。CDialogImpl用于建立简单的对话框,而CAxDialogImpl用于创建包含ActiveX控件的对话框。