C++中的强制类型转换(笔记)
1、基础数据类型的转换
C中的强制类型转换:
int b;
float a = (float) b;
C++中的强制类型转换更像一个函数:
int b;
float a = float(b);
2、static_cast<newtype>(experssion)
将experssion转换为newtype类型,可以用在指针和引用上,也可以用在基础类型和对象上(真正的用途是基础类型和对象上),但是只能转换两者具有一定关系的数据,例如:
#include <iostream>
#include <string>
using namespace std;
class Base {};
class Derived: public Base {};
int main(void)
{
float f = 12.3;
float* pf = &f;
// static cast<>
// OK, n = 12
int n = static_cast<int>(f);
// 错误,“static_cast” : 无法从“float *”转换为“int *”
//int* pn = static_cast<int*>(pf);
//正确
void* pv = static_cast<void*>(pf);
// 编译通过, 但是 *pn2 无意义的东西
int* pn2 = static_cast<int*>(pv);
Base * p_a = new Base;
Derived * p_b = static_cast<Derived*>(p_a);
Base o_a ;
Derived o_b;
o_a = * p_b; //正确,隐式转换,把子对象转换成父对象
o_a = static_cast<Derived>(* p_b); //正确,显式转换,把子对象转换成父对象
//o_b = * p_a; //错误,不存在父对象转换为子对象的情况
//o_b = static_cast<Derived>(* p_a);//错误,不存在父对象转换为子对象的情况
return 0;
}
3、dynamic_cast < new_type > (expression)
该运算符把 expression 转换成 new_type 类型的对象。 new_type 必须是类的指
针、类的引用或者 void*。 dynamic_cast 主要用于类层次间的上行转换和下行转换,还可以
用于类之间的交叉转换。
当对一个指针使用dynamic_cast 时,先尝试转换,如果成功,就返回新类型的合法指针;如果 dynamic_cast 失
败,返回空指针。 dynamic_cast<>转换还有个要求, 需要类成为多态,即包括“虚”函数。
#include <iostream>
#include <string>
#include <exception>
using namespace std;
class Base {
virtual void dummy() {
;
}
};
class Derived: public Base
{
int a;
};
int main (void) {
Base * pba = new Derived;
Base * pbb = new Base;
Derived * pd;
pd = dynamic_cast<Derived*>(pba);
if (pd==0)
cout << "Null pointer on first type-cast.\n";
pd = dynamic_cast<Derived*>(pbb);
if (pd==0)
cout << "Null pointer on second type-cast.\n";
return 0;
}
运行结果:
Null pointer on second type-cast.
4、const_cast< new_type > (expression)
该运算符用来修改类型的 const 或 volatile 属性。除了 const 或 volatile 修饰之外, new_type 和 expression 的类型是一样的。
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
const int var = 21;
//程序会报错, int 类型指针不能初始化指向一个 const 变量,
//int* modifier = &var ;//error C2440: “初始化” : 无法从“const int *”转换为“int *”
//程序会报错, int 类型指针不能初始化指向一个 const 变量,
//int& modifier = constant; // C2440: “初始化” : 无法从“const int”转换为“int &”
//定义一个常量指针指向 constant,类型合法
const int* const_p = &var;
//使用 const_cast 把 const_p 的 const 属于去除
int* modifier = const_cast<int*>(const_p);
*modifier = 123;
cout << "var: "<< var <<endl;
cout << "const_p: "<< *const_p <<endl;
cout << "modifier: "<< *modifier <<endl;
cout<<endl;
cout << "&var: "<< &var <<endl;
cout << "const_p: "<< const_p <<endl;
cout << "modifier: "<< modifier <<endl;
return 0;
}
运行结果:
var: 21
const_p: 123
modifier: 123
&var: 00F8F768
const_p: 00F8F768
modifier: 00F8F768
请按任意键继续. . .
5、reinterpret_cast<new_type> (expression)
reinterpret_cast 运算符是用来处理无关类型之间的转换。它可以把一个指针转换成一个整数,
也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原来类型的指针,
还可以得到原先的指针值), 也可以把进行不同类型指针之间的转换。
IBM 的 C++指南(web 网页) 中明确告诉了我们 reinterpret_cast 应该在什么地方用来作为转换运算
符:
1) 从指针类型到一个足够大的整数类型
2) 从整数类型或者枚举类型到指针类型
3) 从一个指向函数的指针到另一个不同类型的指向函数的指针
4) 从一个指向对象的指针到另一个不同类型的指向对象的指针
5) 从一个指向类函数成员的指针到另一个指向不同类型的函数成员的指针
6) 从一个指向类数据成员的指针到另一个指向不同类型的数据成员的指针
随意在不同类型之间使用 reinterpret_cast,有可能造成程序的破坏和不能使用,比如下边的代码
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
float f = 12.3;
float* pf = &f;
// reinterpret_cast<>
// 错误信息:“reinterpret_cast” : 无法从“float”转换为“int”
// 应该使用 static_cast<> 进行转换
//int i = reinterpret_cast<int>(f);
int* pi = reinterpret_cast<int*>(pf); // 正确
int addr_var = reinterpret_cast<int>(pf); // 正确
typedef int (*funp_t)(int);
int value = 100;
funp_t fun_p;
fun_p = reinterpret_cast<funp_t> (&value);
fun_p(value);
return 0;
}
先是定义一个函数指针的数据类型 funp_t,然后定义一个 funp_t 类型的函数指针fun_p,并使用 reinterpret_cast 运算符号把变量 value 的地址强制转换为函数指针,赋值给 fun_p,最后使用fun_p 函数指针来调用函数, 代码编译没有问题, 但是在运行到 fun_p(value);时候却会报错, 因为fun_p 所指向的地址并不是一个有效的函数存放地址,所以运行异常。 以下是运行异常的界面,这个错误要使用单步调试才能看到,全速运行,并不能出现这个运行异常的界面。
错误的使用 reinterpret_cast 很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确使用 reinterpret_cast 方式。