关于从基类指针向下转换为子类指针
静态检查工具显示以下代码存在违规行为:
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”
描述:避免向下继承层次结构进行强制转换。 此规则检测从基类指针到子类指针的强制转换。
好处:允许向下转换继承层次结构会导致维护问题,并且从基类向下转换始终是非法的。
参考文献:
- Scott Meyers,“有效的 C++:改进程序和设计的 50 种具体方法”,第二版,Addison-Wesley,(C) 2005 Pearson Education, Inc.,章节:“继承和面向对象设计”,项目39
- 联合攻击战斗机、飞行器、C++ 编码标准第 4.23 章类型转换、AV 规则 178
您认为不从基类指针向下转换为子类指针是一个好习惯吗?为什么以及何时应该遵守此规则?
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:
- 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
- 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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
无论编码标准或 OOP 理论如何,reinterpret_cast 在这里肯定是一个坏主意。它必须是
dynamic_cast
或 boost::polymorphic_downcast。至于Effective C++的第39章,它集中讨论了由于必须向下转换为多种不同类型以及必须检查
dynamic_cast
的返回值是否存在潜在故障而导致的维护问题,从而导致了多个分支代码:reinterpret_cast
is certainly a bad idea here, regardless of coding standards or OOP theory. It has to bedynamic_cast
or boost::polymorphic_downcast.As for the chapter 39 of Effective C++, it concentrates on the maintenance problems caused by having to downcast to multiple different types and having to check the return values of
dynamic_cast
for potential failures, resulting in multiple branches in the code:让我们看一下 MFC 中的一些向下转换的示例:
CButton* 来自 CWnd*
CChildWnd* 来自 CFrameWnd*
MFC 设计确实存在一些限制。
由于CWnd提供了MFC中所有窗口类的基本功能,它甚至可以作为View、Dialog、Button等的基类。
如果我们想避免向下转型,可能我们需要MFC hacker将CWnd分成更少的部分?
现在,谈到另一个问题,如何解决违规问题,我的拙见是通过使用安全向下转型来尝试避免不安全的向下转型:
它是使用安全向下转型的良好实践,即使违规仍然存在,我们只是压制违规行为并给出解释。
一些有用的参考:
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
最后,感谢来自大家的各种有用的回应。
他们确实非常有帮助。
Let us go through some of the downcasting example in MFC:
CButton* from CWnd*
CChildWnd* from CFrameWnd*
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:
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.
在我看来,无论如何,你实际上没有必要执行演员阵容,或者至少没有你正在做的那样。您的函数需要返回
CWnd
,因此您无需转换为CSplitFrame
。我本来期望
GetChildWnd
返回一个CWnd*
或类似的;为什么你不能写这样的东西:It doesn't look to me like it is actually necessary for you to perform the cast anyway, or at least not as you are doing it. Your function needs to return a
CWnd
, so you don't need to cast up to aCSplitFrame
.I would have expected that
GetChildWnd
returns aCWnd*
or similar; why can you not write something like:在正确设计的 OOP 代码中,通常应该不惜一切代价避免向下转型类指针。然而,有时这样的转换是必要的,特别是如果您正在使用一些其他库/代码,这些库/代码被设计为需要在客户端代码中进行此类转换。 MFC 就是此类库的一个示例。
当确实需要向下转型时,永远不应该使用
reinterpret_cast
来执行它们。执行转换的正确方法是dynamic_cast
或static_cast
。当人们在代码中看到用于向下转换的 C 风格强制转换并决定将其转换为 C++ 风格强制转换时,人们经常会使用
reinterpret_cast
,错误地假设这种上下文中的 C 风格强制转换是等效的到reinterpret_cast
。实际上,应用于任意方向的父子类型对的 C 风格强制转换相当于static_cast
,但有一些额外的好处(C 风格强制转换可以突破访问保护)。因此,再次强调,为此目的使用 C 风格的转换是错误的,但正确的 C++ 替换不是reinterpret_cast
,而是dynamic_cast
或static_cast
。Downcasting class pointers is generally something that should be avoided at all costs in properly designed OOP code. Nevertheless, sometimes such casts are necessary, especially if you are using some other library/code that was designed to require such casts in the client code. MFC is one example of such library.
When downcasts are really necessary, they should never be performed with
reinterpret_cast
. The proper way to perform the cast is eitherdynamic_cast
orstatic_cast
.Quite often people use
reinterpret_cast
when they see a C-style cast used for downcast in the code and decide to convert it to C++-style cast, incorrectly assuming that a C-style cast in such context is equivalent toreinterpret_cast
. In reality, C-style cast applied to parent-child type pair in any direction is equivalent tostatic_cast
with some extra perks (C-style cast can break through access protection). So, again, using C-style casts for this purpose is wrong, but the proper C++ replacement is notreinterpret_cast
, but ratherdynamic_cast
orstatic_cast
.