1. const_cast
常量指针、引用 与 非常量指针、引用相互转换,转换后仍指向原对象。
/*常量指针转为非常量指针*/
const int* p0 = nullptr;
int* newP0 = const_cast<int*>(p0);
/*非常量指针转为常量指针*/
int* p1 = nullptr;
const int* newP1 = const_cast<const int*>(p1);
2. static_cast
提供编译器认为安全的类型转换。
(1)static_cast用于基本数据类型间的转换
/*char转double*/
char a = 'a';
double d = static_cast<double>(a); // 类似于强制类型转换
double d1 = (double)a;
/*int*转double*,不安全*/
int* p = nullptr;
double* b = static_cast<double*>(p); // 编译器不允许
(2)static_cast用于基类、派生类间指针或引用的转换
注意:使用static_cast将派生类向基类转换是安全的,因为寻址范围缩小;反之则不安全。
以下是微软C++官网的一个示例,详见:微软C++开发者文档
class B { };
class D : public B { };
void f(B* pb, D* pd) {
// B类型的指针转为D类型的指针。不安全,因为寻址范围扩大
D* pd2 = static_cast<D*>(pb);
// D类型的指针转为B类型的指针。安全,因为寻址范围缩小
B* pb2 = static_cast<B*>(pd);
}
3. reinterpret_cast
类似于C的强制类型转换,不保证安全性。
int* p = nullptr;
double* b = reinterpret_cast<double*>(p); // 编译器允许转换,但不安全。
4. dynamic_cast
支持RTTI(Run-Time Type Identification)动态类型识别的基类、派生类的转换。具体什么意思,看如下示例:
基类Base有2个派生类Derive01、Derive02,基类中有虚函数virtual func(),派生类Derive01、Derive02都对该虚函数进行了重写,并且Derive02中还有自己的函数newFunc()。此时main()函数中调用test01()时可以发生多态。如下:
class Base {
public:
virtual void func() { }
};
class Derive01 :public Base {
public:
virtual void func() { cout << "Derive01::func()" << endl; }
};
class Derive02 :public Base {
public:
virtual void func() { cout << "Derive02::func()" << endl; }
void newFunc() { cout<< "Derive02::newFunc()" << endl; }
};
void test01(Base* ptr) { // 可以发生多态
ptr->func();
}
int main() {
Derive01 d01;
Derive02 d02;
test01(&d01); // Derive01::func()
test01(&d02); // Derive02::func()
return 0;
}
现在改变需求:当传给test01()为Derive02类型的指针时,调用其中的newFunc()函数。此时就可以在test01()中使用dynamic_cast来进行转换判断,如下:
void test01(Base* ptr) {
/*
dynamic_cast转换时会检查ptr是否为Derive02*类型:
(如何检查? 通过ptr的vfptr找到vftable, vftable中有RTTI信息)
是则转换成功,将转换后的类型返回给d02ptr;
否则失败,将nullptr返回给d02ptr。
*/
Derive02* d02ptr = dynamic_cast<Derive02*>(ptr);
if (d02ptr == nullptr) { // 为nullptr则表示ptr非Derive02*类型,转换不成功
ptr->func();
} else { // 否则ptr为Derive02*类型
d02ptr->newFunc();
}
}