为什么*一切*在ATL / WTL中使用模板基类

Why does *everything* use a template base class in ATL/WTL?

本文关键字:基类 WTL 一切 ATL 为什么      更新时间:2023-10-16

我在理解 ATL/WTL 代码中模板的用途时遇到了很多麻烦。

当您查看 WTL 时,您会看到如下代码:

template <class TBase>
class CEditT : public TBase
{
    ...
};
typedef CEditT<ATL::CWindow> CEdit;

为什么使用模板基类定义CEditT

换句话说,在什么情况下CEditT<T>会在TCWindow的情况下被实例化?

这样

您就可以重写 ATL/WTL 类调用的ATL::CWindow中的方法。 如果在ATL::CWindow中有一些你不喜欢的东西,你可以使用重写的方法从ATL::CWindow派生一个类,然后将你的新类作为TBase传递。

例如,ATL::CWindow::CenterWindow很长一段时间以来都有一个错误,它没有正确考虑多个监视器,我已经看到人们使用这种技术通过固定的实现覆盖CenterWindow

假设使用组合代替:

template <class TBase> class CEditT {
public:
  TBase base;
  ...
};

这与以下内容没有太大区别:

template <class ITEM> class ListNode {
public:
   ITEM item;
   ListNode<ITEM> *next;
   // ...
};

ListNode可以继承ITEM,就像CEditTTBase所做的那样,但缺点是ITEM不能像int那样成为基本类型。另一方面,ListNode是一种ITEM,这可能是有用的。此外,它将可以访问ITEM的任何protected:部分。

这样它就可以利用奇怪的重复模板模式。如果创建派生类CEditT则定义将class CMyEdit : public CEditT<CMyEdit> 。通过静态地将其this指针强制转换为类,CEditT可以调用您的方法,而无需使用 vtable。

为什么一切都在 ATL/WTL 中使用模板基类?

简而言之,要通过设计模式(而不是C++习语)实现"奇怪的编译时多态性形式",人们可以称为"颠倒继承"作为"指定基类的基类"的技术,以便"允许您将自己的类插入类层次结构"以实现专用类型的灵活性"而无需对任何特定的派生类进行硬编码实现"。

在阅读了由 Jim Beveridge 撰写并由 Visual C++ Developers Journal 于 1999 年 7 月发表的优秀文章 ATL 和颠倒继承 - 了解 ATL 的非典型设计方法后,这一切都应该变得清晰起来。这是指向同一篇文章的完整非分页副本的链接(也在 Wayback Machine 中)。