Search code examples
c++mfccastingstatic-analysiseffective-c++

About downcasting from base class to subclass pointer


A static check tool shows a violation on the below code:

class CSplitFrame : public CFrameWnd  
...
class CVsApp : public CWinApp
CWnd* CVsApp::GetSheetView(LPCSTR WindowText)
{
 CWnd* pWnd = reinterpret_cast<CSplitFrame*>(m_pMainWnd)->m_OutputBar.GetChildWnd(WindowText);
 return pWnd;
}

Error Message: Class 'CSplitFrame' inherits from class 'CWnd'

Description: Avoid casts down the inheritance hierarchy. This rule detects casts from a base class pointer to a subclass pointer.

Benefits: Allowing casts down the inheritance hierarchy leads to maintenance problems, and downcasting from a base class is always illegal.

References:

  1. Scott Meyers, "Effective C++: 50 Specific Ways to Improve Your Programs and Design", Second Edition, Addison-Wesley, (C) 2005 Pearson Education, Inc., Chapter: "Inheritance and Object-Oriented Design", Item 39
  2. JOINT STRIKE FIGHTER, AIR VEHICLE, C++ CODING STANDARDS Chapter 4.23 Type Conversions, AV Rule 178

Do you think it's a good practice for not casting down from a base class pointer to a subclass pointer? Why and When should I follow this rule?


Solution

  • Let us go through some of the downcasting example in MFC:

    CButton* from CWnd*

    CWnd* wnd = GetDlgItem(IDC_BUTTON_ID);
    CButton* btn = dynamic_cast<CButton*>(wnd);
    

    CChildWnd* from CFrameWnd*

    CChildWnd * pChild = ((CSplitFrame*)(AfxGetApp()->m_pMainWnd))->GetActive();
    

    There are indeed some of the limitation of MFC design.

    Due to CWnd provides the base functionality of all window classes in MFC, it does even serve as a base class of View, Dialog, Button etc.

    If we want to avoid downcasting, probably we need MFC hacker to split CWnd into fewer pieces?

    Now, comes to the another question, how to solve the violation, my humble opinion is try to avoid unsafe downcasting, by using safe downcasting:

    Parent *pParent = new Parent;
    Parent *pChild = new Child;
    
    Child *p1 = static_cast<Child*>(pParent);   // Unsafe downcasting:it assigns the address of a base-class object (Parent) to a derived class (Child) pointer
    Parent *p2 = static_cast<Child*>(pChild);   // Safe downcasting:it assigns the address of a derived-class object to a base-class pointer
    

    It serve as good practise for using safe downcasting, even though the violation is still exists, we will just suppress the violation with given explanation.

    Few of the useful reference:
    http://support.microsoft.com/kb/108587
    http://blog.csdn.net/ecai/archive/2004/06/26/27458.aspx
    http://www.codeproject.com/KB/mcpp/castingbasics.aspx
    http://www.bogotobogo.com/cplusplus/upcasting_downcasting.html

    Lastly, thanks for various useful response from all of you.
    They are indeed very helpful.