Direct2D 桌面 window class 模板基于 ATL 的 CWindowImpl

Direct2D desktop window class template based on ATL's CWindowImpl

Kenny Kerr 在他关于 Direct2D 的教程 (part1, part2) 中展示了如何制作简单的 2D 动画时钟并使用以下 classes 层次结构:

//Desktop window class based on ATL's CWindowImpl
template <typename T> struct DesktopWindow :
CWindowImpl<DesktopWindow<T>, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW | WS_VISIBLE>>
{
    // code here, including:
    void Run() {}
};

//ClockSample class which further extends DesktopWindow
template <typename T> struct ClockSample : T
{
    //code here
};

//SampleWindow class which is empty and is needed, as far as I understand,
//to, so to speak, "untemplate" ClockSample template
struct SampleWindow : ClockSample<DesktopWindow<SampleWindow>>
{
    //empty
};

//main function
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    SampleWindow window;
    window.Run();
}

我没有包含实际代码,因为它很大而且与问题无关。

struct SampleWindow : ClockSample<DesktopWindow<SampleWindow>> - 我很难理解哪个 class 继承自哪个以及这里是什么? SampleWindow 继承自 ClockSample,然后又出现了 SampleWindow,它看起来像是对我的循环引用?如果有人能用简单的语言解释这里到底发生了什么,我会很高兴。

SampleWindow 继承自 ClockSample ("untemplates"),后者又派生自 DesktopWindow,后者又派生自 ATL 的 CWindowImpl (进一步以 CWindow 作为基础 class;CWindowHWND window 句柄上的薄包装)。

SampleWindow 作为模板参数允许在代码中 "downcast" 后代 class 并调用覆盖的方法,而无需将它们设为虚拟。这种方法在 ATL 中被大量使用,尤其是。

例如:

template <typename T> struct DesktopWindow :
CWindowImpl<DesktopWindow<T>, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW | WS_VISIBLE>>
{
    // code here, including:
    void Run()
    {
      T* pT = static_cast<T*>(this); // T = SampleWindow
      pT->InternalRun();
    }
};

struct SampleWindow : ClockSample<DesktopWindow<SampleWindow>>
{
    VOID InternalRun()
    {
      // So we eventually reach here
    }
};