条款2 最好使用C++转型操作符
文章目录
- 条款2 最好使用C++转型操作符
- c++4个转型操作符
- static_cast
- const_cast
- dynamic_cast
- reinterpret_cast
- 宏模仿新转换语法
- 欢迎关注公众号【三戒纪元】
c++4个转型操作符
- static_cast
- const_cast
- dynamic_cast
- reinterpret_cast
原因是
- 新式转型方法容易便是出来,而且一眼能看出来是想做什么类型转换。
- 编译器得以判断转型错误(旧式转型无法做到)
static_cast
要从C的旧事转型,改为新的转型方法
(type) expression
==>
static_cast<type> (expression)
static_cast 拥有与C旧事转型相同的威力和意义,以及相同的限制。
const_cast
const_cast 用来改变表达式中的常量性(constness)或易变性(volatileness)
class Widget { ... };
class SpecialWidget : public Widget{ ... };
void update(SpecialWidget* psw) {}
SpecialWidget sw; // sw是一个非const对象
const SpecialWidget& csw = sw; // csw是sw的一个引用,它是一个const对象
update(&csw); // 错误,不能传递一个const SpecialWidget*变量给一个处理SpecialWidget*类型变量的函数
update(const_cast<SpecialWidget*>(&csw)); // 正确,csw的const显示地转换掉(csw和sw两个变量值在update函数中能被更新)
update((SpecialWidget*)&csw); // 同上,但用了一个更难识别的C风格的类型转换
Widget* pw = new SpecialWidget;
update(pw); // 错误,pw的类型是Widget*,但是update函数处理的是SpecialWidget*类型
update(const_cast<SpecialWidget*>(pw)); // 错误,const_cast仅能被用在影响constness or volatileness的地方,不能用在向继承子类进行类型转换
显然,const_cast 最常见的用途就是将某个对象的常量性去除掉。
dynamic_cast
用来执行继承体系中的“安全向下转型或跨系转型动作”。
具体有2个作用:
- 将指向 base class objects的pointers 或 references 转型为 指向 derived(或sibling base) class objects 的 pointers 或 references,并得知转型是否成功。转型失败会返回 null 指针或 1个 expression
- 找出某个对象占用的内存的起始点
class Widget { ... };
class SpecialWidget : public Widget{ ... };
void update(SpecialWidget* psw) {}
void updateViaRef(SpecialWidget& rsw) {}
Widget* pw2 = nullptr;
update(dynamic_cast<SpecialWidget*>(pw2)); // 正确,传递给update函数一个指针是指向变量类型为SpecialWidget的pw2的指针,
// 如果pw2确实指向一个对象,否则传递过去的将是空指针
Widget* pw3 = new SpecialWidget;
updateViaRef(dynamic_cast<SpecialWidget&>(*pw3)); // 正确,传递给updateViaRef函数SpecailWidget pw3指针,
// 如果pw3确实指向了某个对象,否则将抛出异常
double result3 = dynamic_cast<double>(firstNumber) / secondNumber; // 错误,没有继承关系
const SpecialWidget sw4;
update(dynamic_cast<SpecialWidget*>(&sw4)); // 错误,dynamic_cast不能转换掉const
dynamic_cast 只能用来协助你巡航于继承体系中。
reinterpret_cast
这个操作符的转换结果几乎总是与编译平台息息相关,所以 reinterpret_cast 不具有移植性。
reinterpret_cast 最常用的用途是转换“函数指针”类型
比如想将一下函数的一个指针放进 funcPtrArray 中
type void (*FuncPtr); // FuncPtr 是个指针,指向某个函数
// 该函数无需任何自变量,返回值为void
FuncPtr funcPtrArray[10]; // funcPtrArray 是个数组,内有10个 FuncPtrs
int doSth();
funcPtrArray 内各函数指针所指函数的返回值为void,但 doSth 的返回值却是 int:
funcPtrArray[0] = &doSomething; // 错误,类型不匹配
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething); // 编译通过
转换函数指针的代码是不可移植的, C++不保证所有的函数指针都被用一样的方法表示,在一些情况下这样的转换会产生不正确的结果,所以应该避免转换函数指针类型
宏模仿新转换语法
如果编译器不支持新式转型动作,使用宏可达到同样效果
#define static_cast(TYPE, EXPR) ((TYPE)(EXPR))
#define CONST_cast(TYPE, EXPR) ((TYPE)(EXPR))
#define reinterpret_cast(TYPE, EXPR) ((TYPE)(EXPR))
宏方法不能保证转换安全,而且不能得知是否转换成功。