C++ 四种类型转换操作符

时间:2022-05-19 17:45:57

一、C风格类型转换操作符

(type) expression

例子:

int firstNumber, secondNumber;
double result = ((double)firstNumber)/secondNumber;


二、C++类型转换操作符

1.static_cast  在功能上基本上与 C 风格的类型转换一样强大,含义也一样。

double result = static_cast<double>(firstNumber)/secondNumber;

它也有功能上限制。例如,你不能用 static_cast 象用 C 风格的类型转换一样把 struct 转换成 int 类型或者把 double 类型转换成指针类型,另外,static_cast 不能从表达式中去除 const 属性,因为另一个新的类型转换操作符 const_cast 有这样的功能。

2.const_cast 用于类型转换掉表达式的 const 或 volatileness 属性。通过使用 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 最常见的用途就是将某个对象的常量性去除掉。

3. dynamic_cast 用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用 dynamic_cast 把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,而且你能知道转换是否成功。失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时)
Widget *pw;
...
update(dynamic_cast<SpecialWidget*>(pw));
// 正确,传递给 update 函数一个指针
// 是指向变量类型为 SpecialWidget 的 pw 的指针
// 如果 pw 确实指向一个对象,
// 否则传递过去的将使空指针。
void updateViaRef(SpecialWidget& rsw);
updateViaRef(dynamic_cast<SpecialWidget&>(*pw));
//正确。 传递给 updateViaRef 函数
// SpecialWidget pw 指针,如果 pw
// 确实指向了某个对象
// 否则将抛出异常
dynamic_casts 在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上(参见条款 M24),也不能用它来转换掉 constness。
int firstNumber, secondNumber;
double result = dynamic_cast<double>(firstNumber)/secondNumber;
// 错误!没有继承关系

const SpecialWidget sw;
update(dynamic_cast<SpecialWidget*>(&sw));
// 错误! dynamic_cast 不能转换掉 const。
4. reinterpret_cast 的转换结果几乎都是执行期定义( implementation-defined 。 因 此 ,使用reinterpret_casts 的代码很难移植。reinterpret_casts 的最普通的用途就是在函数指针类型之间进行转换。

例如,假设你有一个函数指针数组:

typedef void (*FuncPtr)(); // FuncPtr is 一个指向函数的指针,该函数没有参数,返回值类型为 void
FuncPtr funcPtrArray[10]; // funcPtrArray 是一个能容纳10 个 FuncPtrs 指针的数组
让我们假设你希望(因为某些莫名其妙的原因)把一个指向下面函数的指针存入funcPtrArray 数组:int doSomething();
你不能不经过类型转换而直接去做,因为 doSomething 函数对于 funcPtrArray 数组来说有一个错误的类型。在 FuncPtrArray 数组里的函数返回值是 void 类型,而 doSomething 函数返回值是 int 类型。
funcPtrArray[0] = &doSomething; // 错误!类型不匹配
reinterpret_cast 可以让你迫使编译器以你的方法去看待它们:
funcPtrArray[0] = // this compiles
reinterpret_cast<FuncPtr>(&doSomething);

转换函数指针的代码是不可移植的(C++不保证所有的函数指针都被用一样的方法表示),在一些情况下这样的转换会产生不正确的结果(参见条款 M31),所以你应该避免转换函数指针类型。


三、总结

总结一下就是:

static_cast 和 C 风格的强制类型转换类似,除了不能把struct转换为int、double转化为指针类型这样;

const_cast 用于改变const和volatileness属性,常见的是去掉const属性(把const对象转为非const);

dynamic_cast 用于类继承关系的向下转换,但不能用于缺乏虚函数的类型;

reinterpret_cast 的转换结果是执行期定义的。


参考:More Effective C++ 条款2:尽量使用C++风格的类型转换

相关:C++类型转换及RTTI