我听说static_cast函数应该优于c风格或简单函数风格的强制转换。这是真的吗?为什么?


当前回答

主要原因是经典的C强制转换不区分static_cast<>()、reinterpret_cast<>()、const_cast<>()和dynamic_cast<>()。这四件事是完全不同的。

static_cast<>()通常是安全的。语言中存在有效的转换,或者有适当的构造函数使转换成为可能。唯一有点风险的时候是当你向下转换到一个继承类的时候;您必须确保对象实际上是您所声称的后代,通过语言外部的方式(如对象中的标志)。只要检查结果(指针)或考虑到可能的异常(引用),dynamic_cast<>()就是安全的。

另一方面,reinterpret_cast<>()(或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<”或“reinterpret_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风格的类型转换更危险,而且很难找到它们以确保它们是正确的。

其他回答

一个实用的提示:如果您计划整理项目,可以在源代码中轻松搜索static_cast关键字。

C样式强制转换在代码块中很容易被忽略。c++风格的类型转换不仅是更好的实践;它们提供了更大程度的灵活性。

Reinterpret_cast允许整型到指针类型的转换,但是如果使用不当可能是不安全的。

Static_cast为数值类型提供了良好的转换,例如从enum到int或从int到float或任何您确定类型的数据类型。它不执行任何运行时检查。

另一方面,Dynamic_cast将执行这些检查,标记任何不明确的赋值或转换。它只对指针和引用起作用,会产生开销。

还有一些其他的,但这些是你会遇到的主要的。

这与您希望施加的类型安全性有关。

当你写(bar) foo(如果你没有提供类型转换操作符,这相当于reinterpret_cast<bar> foo)时,你是在告诉编译器忽略类型安全,只做它被告知的事情。

当您编写static_cast<bar> foo时,您是在要求编译器至少检查类型转换是否有意义,并且对于整型类型,要插入一些转换代码。


编辑2014-02-26

这个答案是我5年前写的,但我错了。(见注释)。但它仍然得到了赞!

问题不仅仅是使用static_cast<>还是c风格强制转换,因为使用c风格强制转换时会发生不同的事情。c++强制转换操作符的目的是使这些不同的操作更加显式。

从表面上看,static_cast<>和c风格的强制类型转换似乎是一回事,例如,当将一个值强制转换为另一个值时:

int i;
double d = (double)i;                  //C-style cast
double d2 = static_cast<double>( i );  //C++ cast

这两个函数都将整数值转换为double类型。然而,当使用指针时,事情变得更加复杂。一些例子:

class A {};
class B : public A {};

A* a = new B;
B* b = (B*)a;                                  //(1) what is this supposed to do?

char* c = (char*)new int( 5 );                 //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error

在这个例子中(1)可能没问题,因为A指向的对象实际上是b的一个实例,但如果你不知道在代码中A实际上指向什么呢?

(2)可能是完全合法的(您只想查看整数的一个字节),但它也可能是一个错误,在这种情况下,一个错误将是很好的,如(3)。

c++强制转换操作符旨在通过在可能的情况下提供编译时或运行时错误来暴露代码中的这些问题。

因此,对于严格的“值强制转换”,可以使用static_cast<>。如果你想运行时对指针进行多态转换,请使用dynamic_cast<>。如果真的想忘记类型,可以使用reintrepret_cast<>。而要将const抛出窗外,有const_cast<>。

它们只是让代码更明确,这样看起来你知道你在做什么。

Static_cast意味着您不能意外地使用const_cast或reinterpret_cast,这是一件好事。