1、背景
将类型名作为强制类型转换运算符的做法是C语言的老式做法,C++为保持兼容而予以保留。强制类型转换是有一定风险的,C++引入新的转换机制,主要为了客服C语言转换的三个缺点;
1、没有从形式上体现转换功能和风险的不同。
例如,将int转换位double是没有风险的,而将常量指针转换为非常量指针,将基类指针转换为派生类指针都是高风险的,而且后两者带来的风险不同(可能引发不同的类的错误),C语言的强制类型转换形式对这些不同并不加以区分。
2、将多态基类指针转换为派生类指针不做安全性检查,即无法判断转后的指针确实指向一个派生类指针。
3、难以在程序中寻找到底什么地方做了强制类型转换。
因此,C++引入了4种不同的强制类型转换运算符:
static_cast, reinterpret_cast,const_cast,dynamic_cast
使用方式:
强制类型转换运算符 <要转换到的类型> (待转换的表达式)
例如:
double d = static_cast <double> (3*5); //将 3*5 的值转换成实数
2、static_cast
static_cast 用于比较”自然“和低风险的转换。如整形和浮点型、字符型之间的相互转换。
#include <iostream>
using namespace std;
class A
{
public:
operator int() { return 1; }
operator char*() { return NULL; }
};
int main()
{
A a;
int n;
char* p = "New Dragon Inn";
n = static_cast <int> (3.14); // n 的值变为 3
cout << n << endl; // 输出3
n = static_cast <int> (a); //调用 a.operator int,n 的值变为 1
cout << n << endl; // 输出1
p = static_cast <char*> (a); //调用 a.operator char*,p 的值变为 NULL
cout << p << endl; // 输出空
n = static_cast <int> (p); //编译错误,static_cast不能将指针转换成整型
p = static_cast <char*> (n); //编译错误,static_cast 不能将整型转换成指针
return 0;
}
3、reinterpret_cast
reinterpret_cast用于各种不同类型的指针之间、不同类型的引用之间、指针和能容纳指针的整数类型之间转换。这种转换提供了很强的灵活性,但是转换的安全性只能由程序员保证。
#include <iostream>
using namespace std;
class A {
public:
int i;
int j;
string s = "test";
A(int n) : i(n), j(n) {}
void printA();
};
void A::printA() {
cout << "i = " << i <<", j = " << j << endl;
}
int main() {
A a(100);
a.printA(); // i = 100, j = 100
auto &r = reinterpret_cast<int &>(a); // 强行让r引用a
cout << "r = " << r << endl; // r = 100
r = 200;
a.printA(); //i = 200, j = 100
int n = 300;
A *pa = reinterpret_cast<A *>(&n); // 强行让pa指向n
pa->printA(); // i = 300, j = 1838326408
pa->i = 400;
pa->j = 500; // 此语句不安全,有可能导致程序崩溃
pa->printA(); // i = 400, j = 500
cout << n << endl; // 400
long long la = 0x12345678adcdLL;
pa = reinterpret_cast<A *>(&la); // la 太长,只取低32位0x5678adcd 拷贝给pa
pa->printA(); // i = 1450749389, j = 4660
cout << hex << pa->i << endl; // 5678adcd
typedef void (*PF1) (int);
typedef int (*PF2)(int, char *);
PF1 pf1;
PF2 pf2;
pf2 = reinterpret_cast<PF2>(pf1); //两个不同类型的函数指针之间可以互相转换
return 0;
}
4、const_cast
const_cast 运算符仅用于进行去除const属性的转换,它是4个强制类型转换中唯一能去除const属性的运算符。
const string a = "ddd";
string &p = const_cast<string &>(a);
string *ps = const_cast<string *>(&a);
cout << a << "," << p << "," << *ps << endl; // ddd,ddd,ddd
5、dynamic_cast
用 reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换为派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。dynamic_cast专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。
dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base {
};
int main() {
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 <<"safe dynamic_cast 2" << endl; //不会执行
}
return 0;
}
参考文章:http://c.biancheng.net/view/410.html