主要原因是经典的 C 类型转换不区分我们所说的static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
, and dynamic_cast<>()
。这四件事是完全不同的。
A static_cast<>()
通常是安全的。语言中有一个有效的转换,或者有一个适当的构造函数使之成为可能。唯一有点冒险的时候是当你向下转换为继承类时;您必须通过语言外部的方式(如对象中的标志)确保该对象实际上是您声称的后代。 Adynamic_cast<>()
只要检查结果(指针)或考虑可能的异常(引用),就是安全的。
A reinterpret_cast<>()
(or a const_cast<>()
)另一方面总是危险的。你告诉编译器:“相信我:我知道这看起来不像foo
(这看起来好像它是不可变的),但它是”。
第一个问题是,如果不查看大量分散的代码并了解所有规则,几乎不可能判断 C 风格类型转换中会出现哪一个。
让我们假设这些:
class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
现在,这两个以相同的方式编译:
CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
// Safe; as long as we checked
// but harder to read
然而,让我们看看这段几乎相同的代码:
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reinterpret_cast<>
// and it's wrong!!!
正如您所看到的,如果不了解所有涉及的类,就没有简单的方法来区分这两种情况。
第二个问题是 C 风格的强制转换太难定位。在复杂的表达式中,很难看到 C 风格的强制转换。如果没有成熟的 C++ 编译器前端,几乎不可能编写需要定位 C 风格转换的自动化工具(例如搜索工具)。另一方面,搜索“static_cast
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
// No compiler error.
// but the presence of a reinterpret_cast<> is
// like a Siren with Red Flashing Lights in your code.
// The mere typing of it should cause you to feel VERY uncomfortable.
这意味着,不仅 C 风格的强制转换更加危险,而且找到它们以确保它们正确也更加困难。