自定义MFC窗口/对话框可以是类模板实例化吗?

时间:2010-06-09 10:16:17

标签: c++ templates mfc

MFC在创建对话框时使用了一堆特殊的宏,在我的快速测试中,我在尝试编译模板对话框类时遇到了奇怪的错误。这可能是一个很大的痛苦吗?

这是我试过的:

MyDlg.h

template <class W>
class CMyDlg : public CDialog
{
    typedef CDialog super;
    DECLARE_DYNAMIC(CMyDlg <W>)

public:
    CMyDlg (CWnd* pParent);   // standard constructor
    virtual ~CMyDlg ();

// Dialog Data
    enum { IDD = IDD_MYDLG };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

    DECLARE_MESSAGE_MAP()

private:
    W *m_pWidget; //W will always be a CDialog
};



IMPLEMENT_DYNAMIC(CMyDlg<W>, super) <-------------------

template <class W>
CMyDlg<W>::CMyDlg(CWnd* pParent)
    : super(CMyDlg::IDD, pParent)
{
  m_pWidget = new W(this);
}

我收到了很多错误,但主要错误似乎是:

  

错误C2955:'CMyDlg':使用类   模板需要模板参数   列表

我尝试使用一些专门的模板版本的宏但它没有多大帮助,其他错误改变了,但这个仍然存在。注意我的代码都在一个文件中,因为C ++模板不像普通的那样喜欢.h / .cpp。

我假设过去有人必须这样做,可能会创建自定义版本的宏,但我无法通过搜索找到它,因为“模板”还有其他含义。

4 个答案:

答案 0 :(得分:3)

您可能还有其他问题,但有一点必须是您使用super。这是一个java东西而不是C ++的东西。而不是super,您需要使用CDialog

在查看IMPLEMENT_DYNAMIC宏定义与模板不兼容之后,它在函数定义之前不使用template <class T>语法。您需要做的是定义模板的派生类特化,然后在它们上使用宏。所以你可以这样做:

class MyDlgA : public CMyDlg<A>
{
};

IMPLEMENT_DYNAMIC(MyDlgA, CDialog);

然后为您想要的所有专业化做到这一点。如果这不可行,请查看宏并制作自己的模板化版本。

修改 跟进我的评论,你可以制作一个像这样的宏:

#define INSTANTIATE_DLG_TEMPLATE(T)  \
class MyDlg##T : public CMyDlg<T>    \
{                                    \
};                                   \
                                     \
IMPLEMENT_DYNAMIC(MyDlg##T, CDialog);

然后只需在通常使用typedef的头文件中定义模板特化的地方使用它。

答案 1 :(得分:2)

这是一个可行的解决方案,虽然丑陋......在扩展现有模板并修复模板后,我没有完全重写为宏:

//Template-enabled expansion of IMPLEMENT_DYNAMIC(CMyDlg,super)
template <class W> CRuntimeClass* PASCAL CMyDlg<W>::_GetBaseClass(){ return RUNTIME_CLASS(super); }
template <class W> AFX_COMDAT const CRuntimeClass CMyDlg<W>::CMyDlg= {
        "CMyDlg", sizeof(CMyDlg<W>), 0xFFFF, NULL,&CMyDlg<W>::_GetBaseClass, NULL, NULL };
template <class W> CRuntimeClass* PASCAL CMyDlg<W>::GetThisClass()  { return _RUNTIME_CLASS(CMyDlg); }
template <class W> CRuntimeClass* CMyDlg<W>::GetRuntimeClass() const { return _RUNTIME_CLASS(CMyDlg); }

答案 2 :(得分:1)

我没有为一个对话框做过这个,只有一些自定义控件,但我看不出它为什么不起作用的原因。 我知道至少有一个用于定义消息映射的模板版本,BEGIN_TEMPLATE_MESSAGE_MAP。 查看http://msdn.microsoft.com/en-us/library/aa991537(VS.80).aspx

答案 3 :(得分:0)

由于DECLARE_DYNAMIC宏,出现了许多问题。如果您跟踪宏,则会发现必须定义一个成员变量和三个函数。

template<typename T>
class CTemplateDialogDlg : public CDialogEx
{
    // Construction
public:
    // standard constructor
    CTemplateDialogDlg( CWnd* pParent = nullptr )
        : CDialogEx( IDD_TEMPLATEDIALOGAPP_DIALOG, pParent )
    {}

// Dialog Data
#ifdef AFX_DESIGN_TIME
    enum
    {
        IDD = IDD_TEMPLATEDIALOGAPP_DIALOG
    };
#endif
public:
    T m_tMemberValue;

protected:
    // DDX/DDV support
    virtual void DoDataExchange( CDataExchange* pDX )
    {
        CDialogEx::DoDataExchange( pDX );
    }

protected:
    // Member & Functions from IMPLEMENT_DYNAMIC( CUnitTypeCurvePointDlg, CDialogEx )

    static const CRuntimeClass classCTemplateDialogDlg;
    static CRuntimeClass* PASCAL _GetBaseClass()
    {
        return RUNTIME_CLASS( CDialogEx );
    }
    static CRuntimeClass* PASCAL GetThisClass()
    {
        return (CRuntimeClass*)&classCTemplateDialogDlg;
    }
    virtual CRuntimeClass* GetRuntimeClass() const
    {
        return (CRuntimeClass*)&classCTemplateDialogDlg;
    }
};

然后必须创建成员变量(仅一次)

typedef CTemplateDialogDlg<int> CTemplateDialogIntDlg;
const CRuntimeClass CTemplateDialogIntDlg::classCTemplateDialogDlg;

然后可以使用模板对话框

CTemplateDialogIntDlg Dlg;

但是,由于它绕过了MFC宏,因此您将负责保持成员变量和函数的正确定义。

我还没有解决DECLARE_MESSAGE_MAP问题,但是它们是相似的。