MFC类和C ++样式转换

时间:2017-11-16 08:07:09

标签: c++ casting mfc

我想知道我是否还没有完全理解C ++演员与旧C-Style演员。在MFC中我有这个方法:

CWnd * GetDlgItem(UINT uResId);

我期待来自CWnd的derived的CComboBox(或CEdit)需要这种演员:

dynamic_cast<CComboBox *>(GetDlgItem(IDC_COMBO1));
// for CEdit:
dynamic_cast<CEdit *>(GetDlgItem(IDC_EDIT1));

但是此操作会导致使用空指针崩溃,这意味着强制转换失败。使用:

reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO1));
// for CEdit:
reinterpret_cast<CEdit *>(GetDlgItem(IDC_EDIT1));

解决了这个问题,但我很失望。 我错过了什么?

3 个答案:

答案 0 :(得分:4)

问题是GetDlgItem可能会返回一个临时的CWnd*指针。

如果窗口是CWnd派生类,并且窗口是使用CWnd::Create(Ex)创建的,或者窗口是子类,则RTTI将起作用。

当窗口由Windows创建时(由于对话框模板)并且窗口没有被MFC子类化(DDX_Control ow CWnd::SubclassWindow),GetDlgItem只是使用CWnd*返回临时CWnd::FromHandle。此窗口句柄始终为基本类型CWnd

如果您想检查此窗口是否真的是Edit控件,可以使用CWnd::GetClassName。转换为CEdit*是安全和方便的,因为CEdit控件只通过Window消息与其HWND对应方进行通信。所以这适用于所有基本的集成窗口类。

答案 1 :(得分:3)

  

我想知道我是否还没有完全理解C ++演员与旧C-Style演员。在MFC中我有这个方法:

可能你确实很好地理解了差异,但MFC已经在C ++标准的RTTI之前发布了its own support for RTTI,它不符合标准方式

因此,您可以使用DYNAMIC_DOWNCAST代替,如下所示:

DYNAMIC_DOWNCAST(CEdit, GetDlgItem(IDC_EDIT1));

然而,通常的做法不是强制转换,而是使用DDX_Control来创建代表MFC控件的成员变量,您可以通过右键单击,然后选择添加变量... 或通过MFC Class Wizard

修改

所以我误解了OP关于崩溃何时发生的问题的一个重要部分。崩溃的原因是解除引用nullptr dynamic_cast的有效结果,而不是dynamic_cast本身。

@xMRi解答为何崩溃的原因。

答案 2 :(得分:2)

class A {
public:
    A() {};

    virtual ~A(){}
};

class B : public A {
public:
    B() {};
    virtual ~B() {}
};

int main()
{

    A* a = new A();
    B* b = dynamic_cast<B*>(a);
    // b is 0
    return 0;
}

与winocc.cpp一样

CWnd* CWnd::GetDlgItem(int nID) const
{
    ASSERT(::IsWindow(m_hWnd));

    if (m_pCtrlCont == NULL)
        return CWnd::FromHandle(::GetDlgItem(m_hWnd, nID));
    else
        return m_pCtrlCont->GetDlgItem(nID);
}

和wincore.cpp

CWnd* PASCAL CWnd::FromHandle(HWND hWnd)
{
    CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist
    ASSERT(pMap != NULL);
    CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);

    pWnd->AttachControlSite(pMap);

    ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
    return pWnd;
}

当CHandleMap包含的对象是CWnd而不是CComboBox或任何其他派生类类型时,使用dynamic_cast进行强制转换就不行了。