visual programacion monografia lenguaje introduccion historia entre diferencia definicion c++ casting mfc

programacion - Clases de MFC y moldes de estilo C++



programacion visual c++ (3)

Me pregunto si no he entendido por completo los moldes de C ++ frente al antiguo molde de estilo C. En MFC tengo este método:

CWnd * GetDlgItem(UINT uResId);

Estoy esperando que un CComboBox (o CEdit), que se deriva de CWnd, requiera este tipo de elenco:

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

pero esta operación causa un bloqueo al usar un puntero nulo, lo que significa que el lanzamiento ha fallado. Utilizando:

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

soluciona el problema, pero estoy decepcionado. ¿Qué me estoy perdiendo?


Me pregunto si no he entendido por completo los moldes de C ++ frente al antiguo molde de estilo C. En MFC tengo este método:

Probablemente comprenda bien la diferencia, pero MFC se lanzó antes que RTTI en el estándar C ++, y tiene su propio soporte para RTTI , que no cumple con la norma .

Entonces, como alternativa, podría usar DYNAMIC_DOWNCAST en DYNAMIC_DOWNCAST lugar de la siguiente manera:

DYNAMIC_DOWNCAST(CEdit, GetDlgItem(IDC_EDIT1));

La práctica común para esto, sin embargo, no es lanzar, sino crear una variable miembro que represente su control MFC, utilizando DDX_Control , que puede lograr fácilmente haciendo clic derecho y seleccionando Agregar variable ... o mediante Clase MFC Wizzard .

EDITAR Entonces entendí mal una parte esencial de la pregunta del OP sobre cuándo se produce el bloqueo. El bloqueo se debe a la desreferencia de nullptr , el resultado válido de dynamic_cast , no el dynamic_cast sí. @xMRi responde por qué falla en detalle.


El problema es que GetDlgItem puede devolver un puntero CWnd* temporal.

Si la ventana es una clase derivada de CWnd y la ventana se crea con CWnd::Create(Ex) o la ventana tiene una subclase, RTTI funcionará.

Cuando Windows crea la ventana (debido a una plantilla de diálogo) y la Ventana no está subclasificada por el MFC (con DDX_Control ow CWnd::SubclassWindow ), GetDlgItem simplemente devuelve un CWnd* temporal, con CWnd::FromHandle . Este identificador de ventana siempre es del tipo base CWnd .

Si desea verificar si esta ventana es realmente un control de Edit , puede usar CWnd::GetClassName . La CEdit* a un CEdit* es segura y conveniente porque un control CEdit comunica con su homólogo HWND solo a través de los mensajes de la ventana. Entonces esto funciona para todas las clases básicas de ventanas integradas.


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; }

Como en 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); }

y 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; }

Cuando CHandleMap contiene el objeto es CWnd no un CComboBox o cualquier otro tipo de clase derivada, no funcionará utilizando dynamic_cast para rechazar.