Why ATL Uses Template Classes | CodeGuru

Why ATL Uses Template Classes

Introduction This article discusses why ATL uses template classes. This is not a discussion of ATL features, but just the principle behind the Template library. Let us start with an implementation of the IUnknown interface. We all know that this is an interface that has to be supported by all COM objects. So, I thought […]

Written By
CodeGuru Staff
CodeGuru Staff
May 30, 2002
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Introduction

This article discusses why ATL uses template classes. This is not a discussion of ATL features, but just the principle behind the Template library.

Let us start with an implementation of the IUnknown interface. We all know that this is an interface that has to be supported by all COM objects. So, I thought of implementing this interface, thus making it convenient for everyone writing COM classes to extend it and be happy about IUnknown implementation. My objective is to implement IUnknown once and use it in all the COM classes I write in the future, thus reducing the burden of implementing it every time I write a COM class.

Let us try a method where we implement IUnknown in a class called IUnknownImpl and extend it to derive the IUnknown functionality in other classes.

Here is the C++ definition of the IUnknown interface:

Class IUnknown
{
public:
  virtual HRESULT QueryInterface(REFIID refiid, void **ppv) = 0;
  virtual ULONG    AddRef() = 0;
  virtual ULONG    Release() = 0;
};

The simplest possible implementation of IUnknown interface is as follows:

Class IUnknownImpl : public IUnknown
{
  ULONG m_cRef;
  REFIID  m_IID;

  public:

  IUnknownImpl(REFIID iid) : m_cRef(0), m_IID(iid)
  {
  }

  virtual HRESULT QueryInterface(REFIID refiid, void **ppv)
  {
    if(refiid  == IID_IUnknown || refiid == m_IID)
      *ppv = this;
    //I can not typecast this interface since
    //I don't have an interface to which I need to typecast
    else
      return E_NOINTERFACE;

    static_cast<IUnknown*>(this)->AddRef();

    return S_OK;
  }

  virtual ULONG AddRef()
  {
  return InterlockedIncrement(m_cRef);
  }

  virtual ULONG Release()
  {
    ULONG ul = 0;
    if(0 == (ul = InterlockedDecrement(m_cRef)))
    delete this;

    return ul;
  }
};

Let us define a COM interface called IMyInterface. This interface must extend IUnknown for obvious reasons.

Class IMyInterface : public IUnknown
{
  public:
  virtual HRESULT MyFunction(int iCount) = 0;
};

Because I already have IUnknown implementation, I need not implement IUnknown methods again. I will derive it from the IUnknownImpl class.

Class MyInterfaceImpl : public IMyInterface, IUnknownImpl
{
  public:
    MyInterfaceImpl() : IUnknownImpl(IID_IMyInterface)
    {
    }

    virtual HRESULT MyFunction(int iCount)
    {
    //do something
    return S_OK;
    }
};

Thus we implemented IMyInterface. But this implementation has a problem, visible readily to the minds of seasoned C++ developers. It has the grave diamond problem, as shown in the following illustration.

Let us try to modify IUnknownImpl class so that we avoid this problem. This implementation, instead of extending IUnknown, will implement IUnknown methods of any interface derived from IUnknown.

Template <class BASE_INTERFACE, REFIID iid >
    //BASE_INTERFACE should derive from IUnknown
Class IUnknownImpl2 : public BASE_INTERFACE
{
  ULONG m_cref ;

  public:
  IUnknownImpl(): m_cRef(0) {}

  virtual HRESULT QueryInterface(REFIID refiid, void **ppv)
  {
  if(refiid  == IID_IUnknown || refiid == iid)
    *ppv = static_cast<BASE_INTERFACE*>(this);
    // I have to typecast it to BASE_INTERFACE*, I know that
  else
    return E_NOINTERFACE;

        static_cast<IUnknown*>(this)->AddRef();

        return S_OK;
  }

  virtual ULONG AddRef()
  {
      return InterlockedIncrement(m_cRef);
  }

  virtual ULONG Release()
  {
    	   ULONG ul = 0;
  if(0 == (ul = InterlockedDecrement(m_cRef)))
    delete this;

         return ul;
  }
};

Now I can derive my class MyInterfaceImpl2 from IUnknownImpl2 in this way.

Class MyInterfaceImpl2 : IUnknownImpl2 < IMyInterface,
                                            IID_MYInterface>
{
// my methods
};

The inheritance pattern is now changed to:

The active template library is intended to take care of the COM basic functionalities like Object lifetime and Threading model management, implementation of standard interfaces IUnknown, IDispatch, IClassFactory, and so forth. Using this simple Template library, we can concentrate on implementing our component’s core functionality and forget about the other issues mentioned above.

Templates help us to write generic parameterized classes. As we saw in the above examples, with template-based implementation, we overcame the diamond problem while deriving from an implementation; we could typecast the “this” pointer to the required interface wherever it was required. For further discussion of ATL internals, I would recommend “ATL Internals” by Brent Rector and Chris Sells.

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.