• ATL-style templates


      今天看了一下ATL自动生成的代码框架,然后研究了一下ATL类继承方式,感觉还挺特别的,特地从网上抄了一些例子和说明过来,以后复习时看看。先看一个WTL生成对话框的代码示例:

    #pragma once
    
    class CMainDlg : public CDialogImpl<CMainDlg>, public CUpdateUI<CMainDlg>,
            public CMessageFilter, public CIdleHandler
    {
    public:
        enum { IDD = IDD_MAINDLG };
    
        virtual BOOL PreTranslateMessage(MSG* pMsg);
        virtual BOOL OnIdle();
    
        BEGIN_UPDATE_UI_MAP(CMainDlg)
        END_UPDATE_UI_MAP()
    
        BEGIN_MSG_MAP(CMainDlg)
            MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
            MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
            COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
            COMMAND_ID_HANDLER(IDOK, OnOK)
            COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
            COMMAND_HANDLER(IDOK, BN_CLICKED, OnBnClickedOk)
        END_MSG_MAP()
    
    // Handler prototypes (uncomment arguments if needed):
    //    LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
    //    LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
    //    LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
    
        LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
        LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
        LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
        LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
        LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
    
        void CloseDialog(int nVal);
        LRESULT OnBnClickedOk(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
    };

       这里面可以看到CMainDlg 继承自一个用CMainDlg 初始化的模板类,很神奇,用刚定义的类就能初始化一个父类的模板,其实在C++模板中这个是合法的。只是为什么要这样做呢?下面先看个简化的例子:

    template <class T>
    class B1
    {
    public: 
        void SayHi() 
      {
          // 此处是关键技巧。
          T* pT = static_cast<T*>(this);   
          pT->PrintClassName();
      }
        void PrintClassName() { cout << "This is B1"; }
    };
    
    class D1 : public B1<D1>
    {
        // No overridden functions at all
    };
    
    class D2 : public B1<D2>
    {
        void PrintClassName() { cout << "This is D2"; }
    };
    
    int main()
    {
        D1 d1;
        D2 d2;
        d1.SayHi();    // prints "This is B1"
        d2.SayHi();    // prints "This is D2"
    
        return 0;
    }

      代码还是好懂的,乍一看就是没有用C++“多态”虚函数的特性,而是用了强制数据类型转换,实现了灵活调用子类版本的成员函数。这种技术的优点是这样的:

    1) 不需要使用对象的指针;

    2) 节省内存,因为不需要使用虚函数表;

    3) 不会因为未初始化的虚函数表导致使用NULL指针;

    4) 所有函数的调用在编译时确定,因此它们是可以优化的。

  • 相关阅读:
    【洛谷5304】[GXOI/ZOI2019] 旅行者(二进制分组+最短路)
    【LOJ6485】LJJ 学二项式定理(单位根反演)
    【CF932E】Team Work(第二类斯特林数简单题)
    【CF960G】Bandit Blues(第一类斯特林数)
    【洛谷4689】[Ynoi2016] 这是我自己的发明(莫队)
    【洛谷5355】[Ynoi2017] 由乃的玉米田(莫队+bitset)
    【洛谷5268】[SNOI2017] 一个简单的询问(莫队)
    【洛谷4688】[Ynoi2016] 掉进兔子洞(莫队+bitset)
    【洛谷3653】小清新数学题(数论)
    【洛谷6626】[省选联考 2020 B 卷] 消息传递(点分治基础题)
  • 原文地址:https://www.cnblogs.com/kuliuheng/p/5449542.html
Copyright © 2020-2023  润新知