• 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) 所有函数的调用在编译时确定,因此它们是可以优化的。

  • 相关阅读:
    node中glob模块总结
    HTTP中分块编码(Transfer-Encoding: chunked)
    随笔记录--RegExp类型
    Innodb 表空间传输迁移数据
    千金良方说:"我现在奉上179341字的MySQL资料包,还来得及吗?有"代码段、附录、和高清图!!"
    一不小心,我就上传了 279674 字的 MySQL 学习资料到 github 上了
    MySQL InnoDB Update和Crash Recovery流程
    mysqldump与innobackupex备份过程你知多少
    MySQL 各种超时参数的含义
    mha安装使用手册
  • 原文地址:https://www.cnblogs.com/kuliuheng/p/5449542.html
Copyright © 2020-2023  润新知