有人说C++模板会使代码膨胀,可又人说不会,他的依据是 如果模板会使代码膨胀, 那么ATL和WTL里为什么还要大量使用模板? 同样功能 ,ATL和WTL编译出的可执行文件可比MFC编译的要小的多。我当时一愣 ,事实确实如同事所说,难道模板会使代码膨胀的观点是错误的吗?接下来一起剖析C++模板会不会使代码膨胀。
MFC因为本身代码量和复杂性在那里, 所以它生成比较大的exe无可厚非。我们这里重点关注为什么ATL/WTL使用模板,但是却不会使生成的exe变大。
我们知道使用模板时, 同一模板生成不同的模板实类后会是多份代码 ,比如 vector, vector, vector, 这里总共会生成3份不同的vector代码,这就是我们平时所说的代码膨胀。
那么为什么ATL/WTL就没有代码膨胀的问题呢?
我这里以 ATL里的窗口代码为例来分析这个问题,因为我对WinDbg比较熟悉,下面我会以WinDbg为工具来分析我以前的写得那个俄罗斯方块程序。
首先我们看一下ATL的窗口代码:
template
class ATL_NO_VTABLE CWindowImpl : public CWindowImplBaseT
{
public:
DECLARE_WND_CLASS(NULL)
static LPCTSTR GetWndCaption()
{
return NULL;
}
HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
{
if (T::GetWndClassInfo().m_lpszOrigName == NULL)
T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();
ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
dwStyle = T::GetWndStyle(dwStyle);
dwExStyle = T::GetWndExStyle(dwExStyle);
// set caption
if (szWindowName == NULL)
szWindowName = T::GetWndCaption();
return CWindowImplBaseT::Create(hWndParent, rect, szWindowName,
dwStyle, dwExStyle, MenuOrID, atom, lpCreateParam);
}
};
上面是一个模板类,它应该会生成多份模板实例代码:我们可以用WinDbg的符号搜索命令来做验证:
输入 x HYTeris!ATL::CWindowImpl
0:000> x HYTeris!ATL::CWindowImpl004592f0 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
004343a0 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
00437c90 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
00430440 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
0041c990 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
0044cf50 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
004539a0 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00435800 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00434640 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::~CWindowImpl,ATL::CWinTraits > (void)
00437440 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
00436020 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00453f70 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
00424e30 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
004338a0 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
0041c4f0 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00441b50 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::CWindowImpl,ATL::CWinTraits > (void)
004365f0 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00455120 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::CWindowImpl,ATL::CWinTraits > (void)
0040ea20 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00453fa0 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
0041abc0 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
00459c20 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
0045f640 HYTeris!ATL::CWindowImpl,ATL::CWinTraitsOR > >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
004608a0 HYTeris!ATL::CWindowImpl >::GetWndClassInfo (void)
0045fed0 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00433a70 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
00437c60 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
0044fb70 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
0041acf0 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
00459510 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::GetWndCaption (void)
00437a90 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
00430490 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
00424de0 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
00433ac0 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
00433850 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
00433b60 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
00452050 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
0044f8e0 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
0044cec0 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
004340e0 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
00433ef0 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::~CWindowImpl,ATL::CWinTraits > (void)
004348c0 HYTeris!ATL::CWindowImpl,ATL::CWinTraitsOR > >::~CWindowImpl,ATL::CWinTraitsOR > > (void)
004535b0 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
00454170 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
00459c70 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
00451ed0 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
00451f20 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
0045c4b0 HYTeris!ATL::CWindowImpl >::CWindowImpl > (void)
00436320 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
004536a0 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
004604a0 HYTeris!ATL::CWindowImpl,ATL::CWinTraitsOR > >::GetWndCaption (void)
0040eca0 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
0045ff90 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
00437cc0 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
004366e0 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
0045e620 HYTeris!ATL::CWindowImpl >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
004608d0 HYTeris!ATL::CWindowImpl >::GetWndCaption (void)
004520a0 HYTeris!ATL::CWindowImpl >::~CWindowImpl > (void)
0045d210 HYTeris!ATL::CWindowImpl,ATL::CWinTraitsOR > >::CWindowImpl,ATL::CWinTraitsOR > > (void)
004d84a8 HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d84b8 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d7970 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d7960 HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d914c HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d8dd0 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d8b04 HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d8b14 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d8ae8 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004e31b8 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004e2980 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d88c4 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d8330 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d88f0 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::`RTTI Base Class Array' =
004d88e0 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::`RTTI Class Hierarchy Descriptor' =
004d8a40 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004e30f0 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d8a5c HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d8a6c HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004e21d0 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d8c70 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004e2e78 HYTeris!ATL::CWindowImpl,ATL::CWinTraits > `RTTI Type Descriptor' =
004e1f00 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d9208 HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d9218 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004e1ad8 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d834c HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d835c HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d8c9c HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d8c8c HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d856c HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d855c HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004e2bb8 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d7fa0 HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d7fb0 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d91ec HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004e2048 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d8174 HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d8184 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d8dfc HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004d8dec HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004e2728 HYTeris!ATL::CWindowImpl,ATL::CWinTraits > `RTTI Type Descriptor' =
004e28c8 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d8fac HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::`RTTI Base Class Array' =
004d8f9c HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::`RTTI Class Hierarchy Descriptor' =
004d848c HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d8f80 HYTeris!ATL::CWindowImpl,ATL::CWinTraits >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d8158 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d8540 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d7944 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d7f84 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004e2aa0 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d9168 HYTeris!ATL::CWindowImpl >::`RTTI Class Hierarchy Descriptor' =
004d9178 HYTeris!ATL::CWindowImpl >::`RTTI Base Class Array' =
004e1628 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004e2148 HYTeris!ATL::CWindowImpl > `RTTI Type Descriptor' =
004d95c4 HYTeris!ATL::CWindowImpl,ATL::CWinTraitsOR > >::`RTTI Base Class Array' =
004d95b4 HYTeris!ATL::CWindowImpl,ATL::CWinTraitsOR > >::`RTTI Class Hierarchy Descriptor' =
004e3400 HYTeris!ATL::CWindowImpl,ATL::CWinTraitsOR > > `RTTI Type Descriptor' =
004d9598 HYTeris!ATL::CWindowImpl,ATL::CWinTraitsOR > >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
上面的符号可以验证我们多份实例的猜想。
可以看到 CWindowImpl和我们的窗口继承类(T),窗口基类(TBase), 窗口风格(TWinTraits) 相关,所以数量很多 。 那么为什么这么多的符号,也就是这么多的函数代码 ,exe大小没有被撑大?
那时因为CWindowImpl类函数本身很小, 我们从函数的 代码量上就可以看出来。
用同样的方法 ,我们可以继续分析 CWindowImplBaseT
template
class ATL_NO_VTABLE CWindowImplBaseT : public CWindowImplRoot
{
public:
WNDPROC m_pfnSuperWindowProc;
CWindowImplBaseT() : m_pfnSuperWindowProc(::DefWindowProc)
{}
static DWORD GetWndStyle(DWORD dwStyle)
{
return TWinTraits::GetWndStyle(dwStyle);
}
static DWORD GetWndExStyle(DWORD dwExStyle)
{
return TWinTraits::GetWndExStyle(dwExStyle);
}
virtual WNDPROC GetWindowProc()
{
return WindowProc;
}
static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND Create(HWND hWndParent, _U_RECT rect, LPCTSTR szWindowName,
DWORD dwStyle, DWORD dwExStyle, _U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam = NULL);
BOOL DestroyWindow()
{
ATLASSERT(::IsWindow(m_hWnd));
return ::DestroyWindow(m_hWnd);
}
BOOL SubclassWindow(HWND hWnd);
HWND UnsubclassWindow(BOOL bForce = FALSE);
LRESULT DefWindowProc()
{
const _ATL_MSG* pMsg = m_pCurrentMsg;
LRESULT lRes = 0;
if (pMsg != NULL)
lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);
return lRes;
}
LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
#ifdef STRICT
return ::CallWindowProc(m_pfnSuperWindowProc, m_hWnd, uMsg, wParam, lParam);
#else
return ::CallWindowProc((FARPROC)m_pfnSuperWindowProc, m_hWnd, uMsg, wParam, lParam);
#endif
}
virtual void OnFinalMessage(HWND /*hWnd*/)
{
// override to do something, if needed
}
};
0:000> x HYTeris!ATL::CWindowImplBaseT0040f170 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, unsigned short, void *)
0040ec20 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::GetWndStyle (unsigned long)
00435970 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::OnFinalMessage (struct HWND__ *)
004604d0 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::GetWndStyle (unsigned long)
00434a10 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::~CWindowImplBaseT<:ceditt>,ATL::CWinTraits > (void)
0040ec60 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::GetWndExStyle (unsigned long)
00461740 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::WindowProc (struct HWND__ *, unsigned int, unsigned int, long)
0044c040 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::WindowProc (struct HWND__ *, unsigned int, unsigned int, long)
004346e0 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::~CWindowImplBaseT<:cbuttont>,ATL::CWinTraits > (void)
0041c440 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::CWindowImplBaseT<:cwindow> > (void)
00435940 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::GetWindowProc (void)
00459580 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::GetWndExStyle (unsigned long)
00461950 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, unsigned short, void *)
004395b0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::StartWindowProc (struct HWND__ *, unsigned int, unsigned int, long)
00439ea0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::DefWindowProcW (unsigned int, unsigned int, long)
00461620 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::StartWindowProc (struct HWND__ *, unsigned int, unsigned int, long)
004596e0 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, unsigned short, void *)
0041ced0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::WindowProc (struct HWND__ *, unsigned int, unsigned int, long)
0044c370 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::UnsubclassWindow (int)
00460510 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::GetWndExStyle (unsigned long)
00457f70 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::WindowProc (struct HWND__ *, unsigned int, unsigned int, long)
0045f830 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::GetWindowProc (void)
00457820 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits > (void)
004374b0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::GetWndExStyle (unsigned long)
00434ad0 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::~CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > > (void)
004595c0 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::StartWindowProc (struct HWND__ *, unsigned int, unsigned int, long)
004358f0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::CWindowImplBaseT<:cwindow> > (void)
00445920 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::OnFinalMessage (struct HWND__ *)
00461ad0 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::DefWindowProcW (unsigned int, unsigned int, long)
0041c4c0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::OnFinalMessage (struct HWND__ *)
00437470 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::GetWndStyle (unsigned long)
004398e0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::Create (struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, unsigned short, void *)
0040ed50 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::StartWindowProc (struct HWND__ *, unsigned int, unsigned int, long)
004458a0 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::CWindowImplBaseT<:ceditt>,ATL::CWinTraits > (void)
0045f7e0 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > > (void)
0041ad30 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::~CWindowImplBaseT<:cwindow> > (void)
00430550 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::~CWindowImplBaseT<:cwindow> > (void)
0045f860 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::OnFinalMessage (struct HWND__ *)
004582a0 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::UnsubclassWindow (int)
0041c490 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::GetWindowProc (void)
0044cb50 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::DefWindowProcW (unsigned int, unsigned int, long)
0044c250 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::SubclassWindow (struct HWND__ *)
004458f0 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::GetWindowProc (void)
00459540 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::GetWndStyle (unsigned long)
00458180 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::SubclassWindow (struct HWND__ *)
00457870 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::GetWindowProc (void)
00457910 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::OnFinalMessage (struct HWND__ *)
0040e990 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::DestroyWindow (void)
004396d0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::WindowProc (struct HWND__ *, unsigned int, unsigned int, long)
0041d1c0 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::DefWindowProcW (unsigned int, unsigned int, long)
004578a0 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::DefWindowProcW (unsigned int, unsigned int, long)
004d8fc8 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d8ff4 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::`RTTI Base Class Array' =
004d8fe4 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits >::`RTTI Class Hierarchy Descriptor' =
004d79b4 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::`RTTI Base Class Array' =
004d79a4 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::`RTTI Class Hierarchy Descriptor' =
004e2798 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits > `RTTI Type Descriptor' =
004d819c HYTeris!ATL::CWindowImplBaseT<:cwindow> >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d8938 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::`RTTI Base Class Array' =
004d8928 HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::`RTTI Class Hierarchy Descriptor' =
004d960c HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::`RTTI Base Class Array' =
004d95fc HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::`RTTI Class Hierarchy Descriptor' =
004e2ee8 HYTeris!ATL::CWindowImplBaseT<:cbuttont>,ATL::CWinTraits > `RTTI Type Descriptor' =
004d81c8 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::`RTTI Base Class Array' =
004d81b8 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::`RTTI Class Hierarchy Descriptor' =
004e34a0 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > > `RTTI Type Descriptor' =
004d95e0 HYTeris!ATL::CWindowImplBaseT<:clistviewctrlt>,ATL::CWinTraitsOR > >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004e1f68 HYTeris!ATL::CWindowImplBaseT<:cwindow> > `RTTI Type Descriptor' =
004e1688 HYTeris!ATL::CWindowImplBaseT<:cwindow> > `RTTI Type Descriptor' =
004d7988 HYTeris!ATL::CWindowImplBaseT<:cwindow> >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d890c HYTeris!ATL::CWindowImplBaseT<:ceditt>,ATL::CWinTraits >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
可以看到 CWindowImplBaseT只与 窗口基类和窗口风格相关 ,数量 已经减小很多 ,CWindowImplBaseT模板类本身函数数量不多 ,函数代码量大小也不大 。
然后再看CWindowImplRoot,
template
class ATL_NO_VTABLE CWindowImplRoot : public TBase, public CMessageMap
{
public:
CWndProcThunk m_thunk;
const _ATL_MSG* m_pCurrentMsg;
DWORD m_dwState;
enum { WINSTATE_DESTROYED = 0x00000001 };
// Constructor/destructor
CWindowImplRoot() : m_pCurrentMsg(NULL), m_dwState(0)
{ }
virtual ~CWindowImplRoot()
{
#ifdef _DEBUG
if(m_hWnd != NULL) // should be cleared in WindowProc
{
ATLTRACE(atlTraceWindowing, 0, _T("ERROR - Object deleted before window was destroyed/n"));
ATLASSERT(FALSE);
}
#endif //_DEBUG
}
// Current message
const _ATL_MSG* GetCurrentMessage() const
{
return m_pCurrentMsg;
}
// "handled" management for cracked handlers
BOOL IsMsgHandled() const
{
const _ATL_MSG* pMsg = GetCurrentMessage();
ATLASSERT(pMsg != NULL);
ATLASSERT(pMsg->cbSize >= sizeof(_ATL_MSG));
return pMsg->bHandled;
}
void SetMsgHandled(BOOL bHandled)
{
_ATL_MSG* pMsg = (_ATL_MSG*)GetCurrentMessage(); // override const
ATLASSERT(pMsg != NULL);
ATLASSERT(pMsg->cbSize >= sizeof(_ATL_MSG));
pMsg->bHandled = bHandled;
}
// Message forwarding and reflection support
LRESULT ForwardNotifications(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT ReflectNotifications(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
static BOOL DefaultReflectionHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult);
};
0:000> x HYTeris!ATL::CWindowImplRoot*
004364d0 HYTeris!ATL::CWindowImplRoot<:clistviewctrlt> >::~CWindowImplRoot<:clistviewctrlt> > (void)
004367d0 HYTeris!ATL::CWindowImplRoot<:ceditt> >::~CWindowImplRoot<:ceditt> > (void)
00457c30 HYTeris!ATL::CWindowImplRoot<:cbuttont> >::CWindowImplRoot<:cbuttont> > (void)
00460550 HYTeris!ATL::CWindowImplRoot<:clistviewctrlt> >::CWindowImplRoot<:clistviewctrlt> > (void)
004479d0 HYTeris!ATL::CWindowImplRoot<:ceditt> >::CWindowImplRoot<:ceditt> > (void)
0041c360 HYTeris!ATL::CWindowImplRoot<:cwindow>::~CWindowImplRoot<:cwindow> (void)
00435f40 HYTeris!ATL::CWindowImplRoot<:cbuttont> >::~CWindowImplRoot<:cbuttont> > (void)
004613f0 HYTeris!ATL::CWindowImplRoot<:cwindow>::ForwardNotifications (unsigned int, unsigned int, long, int *)
00438f50 HYTeris!ATL::CWindowImplRoot<:cwindow>::ReflectNotifications (unsigned int, unsigned int, long, int *)
0041c8e0 HYTeris!ATL::CWindowImplRoot<:cwindow>::CWindowImplRoot<:cwindow> (void)
004e2800 HYTeris!ATL::CWindowImplRoot<:ceditt> > `RTTI Type Descriptor' =
004d897c HYTeris!ATL::CWindowImplRoot<:ceditt> >::`RTTI Base Class Array' =
004d896c HYTeris!ATL::CWindowImplRoot<:ceditt> >::`RTTI Class Hierarchy Descriptor' =
004d9640 HYTeris!ATL::CWindowImplRoot<:clistviewctrlt> >::`RTTI Class Hierarchy Descriptor' =
004d9650 HYTeris!ATL::CWindowImplRoot<:clistviewctrlt> >::`RTTI Base Class Array' =
004d8950 HYTeris!ATL::CWindowImplRoot<:ceditt> >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d9028 HYTeris!ATL::CWindowImplRoot<:cbuttont> >::`RTTI Class Hierarchy Descriptor' =
004d9038 HYTeris!ATL::CWindowImplRoot<:cbuttont> >::`RTTI Base Class Array' =
004e16dc HYTeris!ATL::CWindowImplRoot<:cwindow> `RTTI Type Descriptor' =
004e3530 HYTeris!ATL::CWindowImplRoot<:clistviewctrlt> > `RTTI Type Descriptor' =
004d9624 HYTeris!ATL::CWindowImplRoot<:clistviewctrlt> >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d79c8 HYTeris!ATL::CWindowImplRoot<:cwindow>::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004e2f58 HYTeris!ATL::CWindowImplRoot<:cbuttont> > `RTTI Type Descriptor' =
004d79f4 HYTeris!ATL::CWindowImplRoot<:cwindow>::`RTTI Base Class Array' =
004d79e4 HYTeris!ATL::CWindowImplRoot<:cwindow>::`RTTI Class Hierarchy Descriptor' =
004d900c HYTeris!ATL::CWindowImplRoot<:cbuttont> >::`RTTI Base Class Descriptor at (0,-1,0,64)' =
可以看到 CWindowImplRoot只和窗口基类(CWindow)相关 ,所以 相关的符号就更少了。
最后我们再看一下CWindow:
0:000> x HYTeris!ATL::CWindow::*
004e1000 HYTeris!ATL::CWindow::rcDefault = struct tagRECT
00442a20 HYTeris!ATL::CWindow::DestroyWindow (void)
00425730 HYTeris!ATL::CWindow::InvalidateRect (struct tagRECT *, int)
00442340 HYTeris!ATL::CWindow::CenterWindow (struct HWND__ *)
00425850 HYTeris!ATL::CWindow::UpdateWindow (void)
0041c950 HYTeris!ATL::CWindow::CWindow (struct HWND__ *)
004391e0 HYTeris!ATL::CWindow::GetDlgItem (int)
004568a0 HYTeris!ATL::CWindow::SetWindowRgn (struct HRGN__ *, int)
00441d20 HYTeris!ATL::CWindow::GetWindowLongW (int)
00444350 HYTeris!ATL::CWindow::Create (wchar_t *, struct HWND__ *, class ATL::_U_RECT, wchar_t *, unsigned long, unsigned long, class ATL::_U_MENUorID, void *)
004391b0 HYTeris!ATL::CWindow::operator HWND__ * (void)
00459080 HYTeris!ATL::CWindow::EnableWindow (int)
00425140 HYTeris!ATL::CWindow::GetClientRect (struct tagRECT *)
00430c70 HYTeris!ATL::CWindow::SetWindowTextW (wchar_t *)
0040eb30 HYTeris!ATL::CWindow::GetWndClassName (void)
00456770 HYTeris!ATL::CWindow::MoveWindow (int, int, int, int, int)
00442ac0 HYTeris!ATL::CWindow::KillTimer (unsigned int)
00455fc0 HYTeris!ATL::CWindow::GetWindowTextW (wchar_t *, int)
0040ba20 HYTeris!ATL::CWindow::IsWindow (void)
00441db0 HYTeris!ATL::CWindow::GetParent (void)
004315b0 HYTeris!ATL::CWindow::SetWindowPos (struct HWND__ *, int, int, int, int, unsigned int)
00456810 HYTeris!ATL::CWindow::GetWindowRect (struct tagRECT *)
00431860 HYTeris!ATL::CWindow::GetStyle (void)
00455250 HYTeris!ATL::CWindow::Invalidate (int)
004318f0 HYTeris!ATL::CWindow::SetCapture (void)
00442cf0 HYTeris!ATL::CWindow::SetTimer (unsigned int, unsigned int, *)
00431980 HYTeris!ATL::CWindow::ModifyStyle (unsigned long, unsigned long, unsigned int)
00443d10 HYTeris!ATL::CWindow::GetDlgItemTextW (int, wchar_t *, int)
0040b980 HYTeris!ATL::CWindow::SendMessageW (unsigned int, unsigned int, long)
00434be0 HYTeris!ATL::CWindow::ShowWindow (int)
004d7a38 HYTeris!ATL::CWindow::`RTTI Base Class Descriptor at (0,-1,0,64)' =
004d7a04 HYTeris!ATL::CWindow::`RTTI Base Class Descriptor at (4,-1,0,64)' =
004d7a20 HYTeris!ATL::CWindow::`RTTI Class Hierarchy Descriptor' =
004d7a30 HYTeris!ATL::CWindow::`RTTI Base Class Array' =
我们看到CWindow只有一份 , 并且函数数量相比AtlWin.h减少了很多,因为ATL是以源代码的方式提供的 ,所有没有用到的函数不会被编译到我们最终的可执行文件中 。
通过上面的分析 ,相信我们知道了为什么ATL/WTL大量使用模板,但是生成的exe还是这么小的原因 :
不是模板不会使代码膨胀,而是ATL/WTL在设计时就关注了这个问题 ,它避免了在可能生成很多模板实例的模板类中编写大量代码(有些拗口,不知道你有没有读懂^_^)
总结下 ,如果你想用模板,但是又不想 让自己最终的可执行文件变的很大,
有2种方式:
(1)你的模板类不会生成很多模板实例,这样写成模板类还有意义吗?
(2)你的模板类的代码量或是函数个数很少,你可以仿照ATL的方式把模板无关的东西用继承的方式逐层剥离,确保模板类的代码都是和模板参数相关的。
到这里,剖析C++模板会不会使代码膨胀的介绍就算完成了,如果大家还有不清楚地方可以留言给我,如果觉得我写得不错的话,请给我一个大拇指,谢谢!