5

静态检查工具显示违反以下代码:

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. JOINT STRIKE FIGHTER, AIR VEHICLE, C++ 编码标准第 4.23 章类型转换,AV 规则 178

您认为不从基类指针向下转换为子类指针是一个好习惯吗?为什么以及何时我应该遵守这条规则?

4

4 回答 4

10

reinterpret_cast无论编码标准或 OOP 理论如何,这里肯定是个坏主意。它必须是dynamic_castboost::polymorphic_downcast

至于 Effective C++ 的第 39 章,它集中讨论了由于必须向下转换为多种不同类型以及必须检查dynamic_cast潜在故障的返回值而导致的维护问题,从而导致代码中出现多个分支:

重要的是:向下转换总是导致的 if-then-else 编程风格远不如使用虚函数,你应该将它保留在你确实别无选择的情况下。

于 2010-09-30T16:00:58.140 回答
4

让我们看一下 MFC 中的一些向下转换的例子:

来自 CWnd* 的 CButton*

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

CChildWnd* 来自 CFrameWnd*

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

最后,感谢大家的各种有用的回复。
他们确实很有帮助。

于 2010-10-06T02:53:04.310 回答
0

在我看来,无论如何你都不需要执行演员阵容,或者至少不是你正在做的那样。您的函数需要返回 a CWnd,因此您不需要强制转换为 a CSplitFrame

我本来希望GetChildWnd返回一个CWnd*或类似的;为什么你不能写类似的东西:

CWnd* CVsApp::GetSheetView(LPCSTR WindowText)
{
   return m_pMainWnd->m_OutputBar.GetChildWnd(WindowText);
}
于 2010-10-03T22:44:53.700 回答
0

在正确设计的 OOP 代码中,通常应该不惜一切代价避免向下转换类指针。然而,有时这种转换是必要的,特别是如果您正在使用一些其他库/代码,这些库/代码旨在要求在客户端代码中进行这种转换。MFC 就是这种库的一个例子。

当确实需要向下转换时,它们永远不应该使用reinterpret_cast. 执行强制转换的正确方法是dynamic_caststatic_cast

reinterpret_cast当人们在代码中看到用于向下转换的 C 风格转换并决定将其转换为 C++ 风格转换时,人们经常使用,错误地假设这种上下文中的 C 风格转换等同于reinterpret_cast. 实际上,在任何方向上应用于父子类型对的 C 样式转换都相当于static_cast具有一些额外的好处(C 样式转换可以突破访问保护)。因此,再一次,为此目的使用 C 风格的强制转换是错误的,但正确的 C++ 替换不是reinterpret_cast,而是dynamic_castor static_cast

于 2010-10-03T23:08:38.583 回答