简介本文介绍C++中四种功能不同的强制类型转换运算符以进行强制类型转换:static_cast、reinterpret_cast、const_cast 和dynamic_cast。
C++ 引入了四种功能不同的强制类型转换运算符以进行强制类型转换:static_cast、reinterpret_cast、const_cast 和 dynamic_cast。强制类型转换是有一定风险的,有的转换并不一定安全,如把整型数值转换成指针,把基类指针转换成派生类指针,把一种函数指针转换成另一种函数指针,把常量指针转换成非常量指针等。
C++ 强制类型转换运算符语法:
强制类型转换运算符 <要转换到的类型> (待转换的表达式)
static_cast用于基本数据类型之间的转换,如把int转换成char,把int转换成float等等。C++的任何的隐式转换都是使用 static_cast来实现。
用法总结:
1.不能用于不同类型的指针之间互相转换
2.不能用于整型和指针之间的互相转换
3.不能用于不同类型的引用之间的转换
示例代码:
#include <iostream>
using namespace std;
int main()
{
float f = 4.5;
int n;
char c = 'a';
char* p = "C++实战网(www.cppszw.com)";
int* p2 = NULL;
n = static_cast<int>(f); // n的值变为4
n = static_cast<int>(p); // 编译错误,static_cast不能将指针转换成整型
p = static_cast<char*>(n); // 编译错误,static_cast不能将整型转换成指针
p2 = static_cast<int*>(&c); // 编译错误,static_cast不能将字符转换成指针
return 0;
}
reinterpret_cast用于转换任何类型的另一个指针的一个指针,而不管该类是否相互关联。它不检查指针类型和指针所指向的数据是否相同。
用法总结:
1.用于进行各种不同类型的指针之间的互相转换
2.用于不同类型的引用之间的互相转换
3.用于指针和能容纳指针的整数类型之间的转换
示例代码1:
int* p = new int(65);
char* ch = reinterpret_cast<char*>(p);
cout << *p << endl;
cout << *ch << endl;
cout << p << endl;
cout << ch << endl;
编译输出:
示例代码2:
class A
{
public:
int i;
int j;
A(int n) :i(n), j(n) { }
};
void test_reinterpret_cast2()
{
A a(100);
int &r = reinterpret_cast<int&>(a); // 强行让 r 引用 a
r = 200; // 把 a.i 变成了 200
cout << a.i << "," << a.j << endl; // 输出 200,100
int n = 300;
A *pa = reinterpret_cast<A*> (&n); // 强行让 pa 指向 n
pa->i = 400; // n变成400
pa->j = 500; // 此条语句不安全,很可能导致程序崩溃
cout << n << endl; // 输出 400
long long la = 0x12345678abcdLL;
pa = reinterpret_cast<A*>(la); // la太长,只取低32位0x5678abcd拷贝给pa
unsigned int u = reinterpret_cast<unsigned int>(pa);// pa逐个比特拷贝到u
cout << hex << u << endl; // 输出 5678abcd
typedef void(*PF1) (int);
typedef int(*PF2) (int, char *);
PF1 pf1; PF2 pf2;
pf2 = reinterpret_cast<PF2>(pf1); // 两个不同类型的函数指针之间可以互相转换
}
编译输出:
第 17 行的代码不安全,因为在编译器看来,pa->j 的存放位置就是 n 后面的 4 个字节。 本条语句会向这 4 个字节中写入 500。但这 4 个字节不知道是用来存放什么的,贸然向其中写入可能会导致程序错误甚至崩溃。
示例代码3:
// 结构体mystruct
struct mystruct {
int x;
int y;
char c;
bool b;
};
void test_reinterpret_cast3()
{
mystruct s;
s.x = 5;
s.y = 10;
s.c = 'a';
s.b = true;
// 在强制转换期间,数据类型必须与原始数据类型相同
// 将's'指针转换为'p'中int类型的指针。
int* p = reinterpret_cast<int*>(&s);
cout << sizeof(s) << endl;
// 打印当前由*p指向的值
cout << *p << endl;
// 将指针增加1
p++;
// 打印下一个整数值
cout << *p << endl;
p++;
// 用char *ch将char *指向p。
char* ch = reinterpret_cast<char*>(p);
// 打印(*ch)指定的字符值
cout << *ch << endl;
ch++;
bool* n = reinterpret_cast<bool*>(ch);
cout << *n << endl;
cout << *(reinterpret_cast<bool*>(ch)) << endl;
}
编译输出:
示例代码4:
#include <iostream>
using namespace std;
class A {
public:
void fun_a()
{
cout << " In class A\n";
}
};
class B {
public:
void fun_b()
{
cout << " In class B\n";
}
};
int main(int argc, char const *argv[])
{
// 创建B类的对象
B* x = new B();
// 将指向B类引用的对象的指针转换为A类
A* new_a = reinterpret_cast<A*>(x);
// 访问A类的函数。
new_a->fun_a();
return 0;
}
编译输出:
const_cast 运算符仅用于进行去除 const 属性的转换,它也是四个强制类型转换运算符中唯一能够去除 const 属性的运算符。
示例代码:
// const_cast
void test_const_cast()
{
const string s = "C++实战网(www.cppszw.com)";
// s = "Hello World!"; // 编译出错:const修饰符不支持修改
string& p = const_cast<string&>(s);
p = "Hello World!";
cout << p.c_str() << endl; // 输出:Hello World!
}
编译输出:
用 reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换为派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。dynamic_cast专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。
dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。
示例代码:
// dynamic_cast
class Base
{
public:
virtual ~Base() {}
};
class Derived : public Base { };
void test_dynamic_cast()
{
Base b;
Derived d;
Derived* pd;
pd = reinterpret_cast <Derived*> (&b);
if (pd == NULL)
// 此处pd不会为 NULL。reinterpret_cast不检查安全性,总是进行转换
cout << "unsafe reinterpret_cast" << endl; // 不会执行
pd = dynamic_cast <Derived*> (&b);
if (pd == NULL) // 结果会是NULL,因为 &b 不指向派生类对象,此转换不安全
cout << "unsafe dynamic_cast1" << endl; // 会执行
pd = dynamic_cast <Derived*> (&d); // 安全的转换
if (pd == NULL) // 此处 pd 不会为 NULL
cout << "unsafe dynamic_cast2" << endl; // 不会执行
}
编译输出:
参考:
本文向大家介绍一个C++实战项目:C++实现雪花算法(SnowFlake)产生唯一ID,主要涉及雪花算法、算法知识等,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文介绍一个C++代码片段:如何在C++中删除一个文件目录下的所有文件及目录,感兴趣的朋友可以参考一下。
本文介绍C++实现C++实现8种排序算法,主要包括冒泡排序、插入排序、二分插入排序、希尔排序、直接选择排序、堆排序、归并排序、快速排序,直接上代码,感兴趣的朋友可以参考一下。
本文介绍C++实现线程同步的四种方式:事件对象、互斥对象、临界区、信号量,感兴趣的朋友可以参考一下。
本文介绍C++内存泄漏的检测与定位方法,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++实现一个多线程安全的队列容器模板类,主要涉及C++模板类的使用、互斥体实现多线程安全、队列数据结构等知识,具有一定的C++实战价值,感兴趣的朋友可以参考一下。