> First, a minor WTL-related design issue:
>
> "template <class _T>
> class CMyXMLBase : public CExpatImpl <_T> "
>
> I can't figure out why everyone keeps doing that. In this case, it's
> probably a doggerel version of the Abstract Template Design Pattern. If so,
> make CExpatImpl into a concrete class and an abstract interface (IExpat, for
> example). Then CMyXMLBase inherits IExpat and resolves any methods we need
> in it, such as OnStartElement or OnEndElement.
Appendix A of ATL Internals talks about this, as well as an article on devx [1].
It's been called "simulated dynamic binding", "ATL style inheritance", "upside
down inheritance", "static polymorphism", and other things. Its used quite a
bit in ATL / WTL for various base classes. Its not mutually exclusive to an
interface, but is often used in conjunction with an interface (such as
IDispatchImpl, IProvideClassInfo2Impl, etc.). Its also the technique used by of
all the "mixin" windowing base classes of ATL / WTL (CWindowImpl, etc.).
Using this approach, in the base class you do something like:
T* pT = static_cast<T*>(this);
pT->OverrideableFunction();
Its essentially like having "OverrideableFunction" be a virtual function, but
with a couple of benefits:
1. It saves at least 2 levels of indirection (with a virtual function pointer
and virtual function table) at run-time.
2. The calculations for a static_cast<> are performed at compile time, so the
code can be optimized better because its a compile time thing rather than a
run-time thing (the compiler might even be able to inline the function call -
which would be impossible if using a virtual function).
3. It can possibly save you from needing a v-table and virtual function
pointer all together - which saves at least the 4 byte virtual function pointer
per instance, plus the size of the virtual table.
4. Your base class doesn't have to define the method - thus acting like a pure
virtual function that has to be defined in derived classes or you get compile
errors.
5. You can call static methods on the derived class. (And technically you
could use public member variables as well - both static and non-static.)
6. Other stuff I'm forgetting I'm sure.
Item #5 can't be done with virtual classes and functions even if you wanted to.
Just one of the many examples of this in ATL is when you are making a COM object
with ATL - you define "BEGIN_COM_MAP", which expands to you defining a handful
of static methods and members that the base class CComObjectRootEx calls to help
implement QueryInterface.
Now that's not to say that every single bit of code using "template <T> class
Base : public T" always do things right, or that the author understood what its
doing. I haven't look at CExpatImpl, so I can't speak to its use. But if you
use the technique correctly, its a good thing IMO.
-Daniel
[1] <http://archive.devx.com/free/mgznarch/vcdj/1999/julmag99/atlinherit1.asp>