簡體   English   中英

關於從基類到子類指針的向下轉換

[英]About downcasting from base class to subclass pointer

靜態檢查工具顯示違反以下代碼:

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

錯誤消息:類'CSplitFrame'繼承自'CWnd'類

描述:避免強制轉換繼承層次結構。 此規則檢測從基類指針到子類指針的強制類型轉換。

好處:允許強制轉換繼承層次結構會導致維護問題,而從基類進行向下轉換始終是非法的。

參考文獻:

  1. Scott Meyers,“有效的C ++:50種改進程序和設計的具體方法”,第二版,Addison-Wesley,(C)2005 Pearson Education,Inc。,章節:“繼承和面向對象設計”,第39項
  2. 聯合攻擊手,空中車輛,C ++編碼標准第4.23章類型轉換,AV規則178

你認為不從基類指針轉換為子類指針是一個好習慣嗎? 為什么以及何時應遵循此規則?

無論編碼標准還是OOP理論, reinterpret_cast在這里肯定是個壞主意。 它必須是dynamic_castboost :: polymorphic_downcast

至於Effective C ++的第39章,它集中討論由於必須向下轉換為多個不同類型而導致的維護問題,並且必須檢查dynamic_cast的返回值以查找潛在的故障,從而導致代碼中的多個分支:

重要的是:if-then-else的編程方式,即向下轉換總是導致它遠遠低於虛函數的使用,你應該在你真正無可奈何的情況下保留它。

讓我們來看看MFC中的一些向下轉換示例:

來自CWnd *的CButton *

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

來自CFrameWnd *的CChildWnd *

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

確實有一些MFC設計的局限性。

由於CWnd提供了MFC中所有窗口類的基本功能,它甚至可以作為View,Dialog,Button等的基類。

如果我們想避免向下轉發,我們可能需要MFC黑客將CWnd分成更少的部分?

現在,談到另一個問題,如何解決違規行為,我的拙見是盡量避免不安全的向下轉型,使用安全的轉發:

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

它是使用安全向下轉換的良好做法,即使違規行為仍然存在,我們也會根據給定的解釋來壓制違規行為。

幾個有用的參考:
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

最后,感謝各位的各種有用回應。
他們確實非常有幫助。

它看起來並不像你實際上有必要進行演員表演,或者至少不像你一樣。 您的函數需要返回CWnd ,因此您不需要轉換為CSplitFrame

我原以為GetChildWnd返回CWnd*或類似的東西; 為什么你不能這樣寫:

CWnd* CVsApp::GetSheetView(LPCSTR WindowText)
{
   return m_pMainWnd->m_OutputBar.GetChildWnd(WindowText);
}

在適當設計的OOP代碼中,傾向於通常應該避免使用向下轉換類指針。 盡管如此,有時候這樣的強制轉換是必要的,特別是如果你使用的是其他一些設計用於在客戶端代碼中需要這些強制轉換的庫/代碼。 MFC就是這種庫的一個例子。

當真正需要向下轉換時,永遠不應該使用reinterpret_cast執行它們。 執行static_cast的正確方法是dynamic_caststatic_cast

人們經常使用reinterpret_cast當他們在代碼中看到用於向下轉換的C風格轉換並決定將其轉換為C ++風格的轉換時,錯誤地假設在這樣的上下文中的C風格轉換等同於reinterpret_cast 實際上,在任何方向上應用於父子類型對的C樣式轉換等同於具有一些額外特權的static_cast (C樣式轉換可以突破訪問保護)。 因此,再次使用C風格的強制轉換是錯誤的,但正確的C ++替換不是reinterpret_cast ,而是dynamic_caststatic_cast

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM