本文主要介绍一下C++推荐使用的4个强制类型转换关键字:static_cast、reinterpret_cast、const_cast 以及 dynamic_cast。
该关键字是四种关键字中最常见的。用法为:
static_cast <new_type> (expression)
目的是将 expression 转换为new_type 类型。
该关键字具有如下特点:
下面是几个使用static_cast的场景:
场景1:非多态类型的转换(float向int类型转换)
#include
using namespace std;
int main(int argc, char const *argv[])
{
float f = 4.5;
int a = f; //C-style
int b = static_cast<int>(f);
cout << b << endl; //输出为4
return 0;
}
但是并不是所有的非多态类型都可以互相转换的,例如:
#include
using namespace std;
int main(int argc, char const *argv[])
{
int a = 10;
char c = 'a';
int* q = (int*) &c;
int *p = static_cast<int *>(&c);//编译错误,static_cast 不能将字符转换成指针
return 0;
}
场景2:继承中的强制类型转换
#include
using namespace std;
class Base {
};
class Derived : public Base {
};
int main(int argc, char const *argv[])
{
Derived d1;
Base* b1 = (Base*)(&d1); // 允许
Base* b2 = static_cast<Base*>(&d1); //允许
return 0;
// 运行无报错
}
如果修改代码,把继承改为private则会出现错误
#include
using namespace std;
class Base {
};
class Derived : private Base {
};
int main(int argc, char const *argv[])
{
Derived d1;
Base* b1 = (Base*)(&d1); // 允许
Base* b2 = static_cast<Base*>(&d1); //不允许,出错
return 0;
}
因此,要使用static_cast,请将其继承为public。
场景3:将“向空指针”和“从空指针”进行强制转换
#include
using namespace std;
int main(int argc, char const *argv[])
{
int i = 10;
void* v = static_cast<void*>(&i);
int* ip = static_cast<int*>(v);
return 0;
}
const_cast运算符仅用于删除 const、volatile 和 __unaligned 特性的转换.
const string s = "Inception";
string& p = const_cast<string&> (s);
string* ps = const_cast<string*> (s);
reinterpret_cast 用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。它不检查指针类型和指针所指向的数据是否相同。
这种转换提供了很强的灵活性,但转换的安全性只能由程序员的细心来保证了。例如,程序员执意要把一个 int* 指针、函数指针或其他类型的指针转换成 string* 类型的指针也是可以的,至于以后用转换后的指针调用 string 类的成员函数引发错误,程序员也只能自行承担查找错误的烦琐工作。
用法如下:
reinterpret_cast <数据类型*>(指针变量);
使用reinterpret_cast的目的:
一个简单的例子:
#include
using namespace std;
int main(int argc, char const *argv[])
{
int* p = new int(65);
char* ch = reinterpret_cast<char*>(p);
cout << *p << endl; // 65
cout << *ch << endl; // A
cout << p << endl; //0x19a6010
cout << ch << endl; //A
return 0;
}
另一个例子:
#include
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(); // 输出In class A
return 0;
}
用 reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换为派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。dynamic_cast专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。
dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。
例子:
#include
#include
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 << "unsafe dynamic_cast2" << endl; //不会执行
return 0;
}
参考:
C++强制类型转换运算符(static_cast、reinterpret_cast、const_cast和dynamic_cast).
C++四种强制类型转换运算符.