Reputation: 2440
I'm wondering if I haven't fully understood C++ casts versus old C-Style cast. In MFC I have this method:
CWnd * GetDlgItem(UINT uResId);
I'm expecting that a CComboBox (or CEdit), which is derived from CWnd, requires this kind of cast:
dynamic_cast<CComboBox *>(GetDlgItem(IDC_COMBO1));
// for CEdit:
dynamic_cast<CEdit *>(GetDlgItem(IDC_EDIT1));
but this operation causes a crash for using null pointer, that means that cast have failed. Using:
reinterpret_cast<CComboBox *>(GetDlgItem(IDC_COMBO1));
// for CEdit:
reinterpret_cast<CEdit *>(GetDlgItem(IDC_EDIT1));
fixes the problem, but I'm disappointed. What am I missing?
Upvotes: 4
Views: 1755
Reputation: 5713
I'm wondering if I haven't fully understood C++ casts versus old C-Style cast. In MFC I have this method:
Probably you do understand the difference well, but MFC had been released before the RTTI in the C++ standard, having its own support for RTTI, which doesn't meet the standard way.
So alternatively, you could use DYNAMIC_DOWNCAST
instead as follows:
DYNAMIC_DOWNCAST(CEdit, GetDlgItem(IDC_EDIT1));
The common practice for this, however, is not to cast, but to create a member variable that represents your MFC control, using DDX_Control, which you can easily accomplish by doing Right Click, and selecting Add Variable... or through MFC Class Wizard.
EDIT
So I misunderstood an essential part of the OP's question about when the crash occurs. The crash is because of dereferencing nullptr
, the valid result of dynamic_cast
, not the dynamic_cast
itself.
@xMRi answers why it crashes in detail.
Upvotes: 4
Reputation: 54
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;
}
As in 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);
}
and 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;
}
When CHandleMap contains the object is CWnd not a CComboBox or any other derived class type, it will not ok by using dynamic_cast to cast down.
Upvotes: 2
Reputation: 15375
The problem is that GetDlgItem
may return a temporary CWnd*
pointer.
If the window is a CWnd
derived class and the window is created with CWnd::Create(Ex)
or the window is subclassed, RTTI will work.
When the window is created by Windows (due to a dialog template) and the Window isn't subclassed by the MFC (with DDX_Control
ow CWnd::SubclassWindow
), GetDlgItem
just returns a temporary CWnd*
, with CWnd::FromHandle
. This window handle is always of the base type CWnd
.
If you want to check if this window is really a Edit
control you can use CWnd::GetClassName
. Casting to a CEdit*
is safe and convenient because a CEdit
control communicates with it's HWND
counterpart just via Window messages. So this works for all basic integrated window classes.
Upvotes: 5