static_cast<new_type>(expression)
dynamic_cast<new_type>(expression)
const_cast<new_type>(expression)
reinterpret_cast<new_type>(expression)
一、static_cast
static_cast相当于传统的C语言里的强制转换,该运算符把expression转换为new_type类型,用来强迫隐式转换,但没有运行时类型检查来保证转换的安全性。
它主要有如下几种用法:
- 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
- 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的(派生类必定包含基类的成员和方法);
- 进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
- 用于基本数据类型之间的转换,如把double转换成int,把int转换成enum。这种转换的安全性也要开发人员来保证。
- 把任何类型的表达式转换成void类型。
static_cast不能转换掉expression的const、volatile。
如果涉及到类的话,static_cast
只能在有相互联系的类型中进行相互转换,不一定包含虚函数。
/* 常规的使用方法 */
float f_pi=3.141592f
int i_pi=static_cast<int>(f_pi); /// i_pi 的值为 3
/* class 的上下行转换 */
class Base{
// something
};
class Sub:public Base{
// something
}
// 上行 Sub -> Base
//编译通过,安全
Sub sub;
Base *base_ptr = static_cast<Base*>(&sub);
// 下行 Base -> Sub
//编译通过,不安全
Base base;
Sub *sub_ptr = static_cast<Sub*>(&base);
二、dynamic_cast
主要用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换(只能用于类间转换,支持类间交叉转换,不能操作普通数据。)(转换之后可以调用转换之后对象的函数)
(1)在类的转换时,在类层次间进行上行转换时,dynamic_cast
和static_cast
的效果是一样的。在进行下行转换时,dynamic_cast
具有类型检查的功能,比static_cast
更安全。
- 向上转换,即为子类指针指向父类指针(一般不会出问题);向下转换,即将父类指针转化子类指针。
- 向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
- 在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。
Dynamic_cast
操作符则可以在运行期对可能产生问题的类型转换进行测试。
(2)发生多态时,允许互相转换。
(3)无继承关系的类之间也可以相互转换,类之间的交叉转换。
(4)如果dynamic_cast
语句的转换目标是指针类型并且失败了,则结果为null指针。如果转换目标是引用类型并且失败了,则dynamic_cast
运算符将抛出一个std::bad_cast
异常
(5)使用 dynamic_cast
进行转换的,基类中一定要有虚函数,否则编译不通过(类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义)。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。
class base {
public:
void print1() { cout << "in class base" << endl; }
};
class derived : public base {
public:
void print2() { cout << "in class derived" << endl; }
};
int main() {
derived* p, * q;
// p = new base; // Compilr Error: 无法从 "base * " 转换为 "derived * "
// Compile Error: Cannot cast from 'base*' to 'derived*' via dynamic_cast: expression type is not polymorphic(多态的)
// p = dynamic_cast<derived *>(new base);
q = static_cast<derived*>(new base); // ok, but not recommended(推荐)
q->print1(); // in class base
q->print2(); // in class derived
return 0;
}
#include <iostream>
#include <string>
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); // 此处pd不会为 NULL。reinterpret_cast不检查安全性,总是进行转换
if (pd == NULL)
cout << "unsafe reinterpret_cast" << endl; // 不会执行
pd = dynamic_cast <Derived*> (&b); // 结果会是NULL,因为 &b 不指向派生类对象,此转换不安全
if (pd == NULL)
cout << "unsafe dynamic_cast1" << endl; // 会执行
pd = dynamic_cast <Derived*> (&d); // 安全的转换,此处 pd 不会为 NULL
if (pd == NULL)
cout << "unsafe dynamic_cast2" << endl; // 不会执行
return 0;
}
三、const_cast
const_cast
,用于修改类型的const
或volatile
属性,只能对是 引用 或者 指针 的变量添加或移除const
。(除了const
或volatile
修饰之外, type_id
和expression
的类型是一样的。)
const_cast
则正是用于强制去掉这种不能被修改的常数特性,但需要特别注意的是const_cast
不是用于去除变量的常量性,而是去除 指向常数对象的指针或引用 的常量性,其去除常量性的对象必须为指针或引用。
- 常量指针被转化成非常量指针,并且仍然指向原来的对象;
- 常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。
const int g = 20;
int *h = const_cast<int*>(&g);//去掉const常量const属性
const int g = 20;
int &h = const_cast<int &>(g);//去掉const引用const属性
const char *g = "hello";
char *h = const_cast<char *>(g);//去掉const指针const属性
四、reinterpret_cast
reinterpret_cast是强制类型转换符用来处理无关类型转换的,并且其不可移植。他是用在任意的指针之间的转换,引用之间的转换,指针和足够大的int型之间的转换,整数到指针的转换。
五、RTTI(Run-Time Type Identification)
通过运行时类型信息程序能够使用 基类的指针或引用 来检查这些指针或引用所指的对象的实际派生类型。(运行时类型识别)