C++箴言:将强制转型减到最少
C++的规则旨在确保不会出现类型错误。理论上,如果你的程序想顺利编译,就不要试图对任何对象做任何不安全或无意义的操作。这是一个非常有价值的保证,你不应该轻易放弃。
不幸的是,强制转换破坏了类型系统。会引起各种各样的麻烦,有的很容易察觉,有的却格外微妙。如果你从C,Java,或者C#转到C++,请注意,因为强制转换在那些语言中比在C++中更有必要,危险性更小。但C++不是C,也不是Java,更不是C#。在这种语言中,强制转换是一个你必须全神贯注才能接近的特性。
我们先来回顾一下强制转换的语法,因为通常有三种不同的方式来编写同一个强制转换。C-style (C-style)强制转换如下:
(T)表达式//将表达式转换为T类型
函数式强制转换使用以下语法:
T(expression) //将表达式转换为T类型
两种形式没有本质区别,纯粹是括号放在哪里的问题。我把这两种形式称为旧风格的强制改造。
同时,C++提供了四种新的强制转换形式(通常称为new style或C++ style强制转换):
const_cast(表达式)
动态转换(表达式)
reinterpret_cast(表达式)
static_cast(表达式)
每一种都适用于特定的用途:
const_cast一般用于强制消除对象的恒常性。能做到这一点的是C++风格的强制转换。
dynamic_cast主要用于执行“安全向下转换”,即判断一个对象是否是继承系统中的特定类型。这是一种强制转换,不能用旧式语法来执行。这也是一种强制转换,可能会产生巨大的运行时成本。稍后我会提供细节。)
reinterpret_cast专门用于底层强制转换,导致实现依赖(即不可移植),比如将指针转换为整数。这种强制转换在底层代码之外应该是极其罕见的。我在这本书里只用过一次,而且是在讨论你应该如何为* raw内存写一个调试分配器的时候。
static_cast可用于强制隐式转换(例如,将非const对象转换为const对象(如第3项),将int转换为double,等等)。它还可以用于许多此类转换的反向转换(例如,void*指针到类型化指针,基类指针到派生类指针),但它不能将const对象转换为非const对象。(只有const_cast能做到。)
旧样式的强制转换仍然合法,但新形式更可取。首先,它们在代码中更容易被识别(无论是人还是grep这样的工具),这简化了在代码中查找类型系统哪里被破坏的过程。其次,更准确地指定每个强制转换的目的使得编译器能够诊断使用错误。例如,如果您尝试使用const_cast之外的新样式来强制转换以消除恒定性,您的代码将无法编译。
当我想调用一个显式的构造函数将一个对象传递给一个函数时,这可能是我唯一一次使用旧式的造型。例如:
类小部件{
公共:
显式小部件(int size);
...
};
void doSomeWork(const Widget w);
doSomeWork(Widget(15));//从int创建小部件
//带函数式cast
doSomeWork(static _ cast(15));//从int创建小部件
//带有C++样式的强制转换
位律师回复
0条评论