static_cast
🔷允许执行任意的隐式转换和相反转换
🔷没有运行时类型检查来保证转换的安全性
🔷进行上行转换(把派生类的指针或引用转换成基类表示)是安全的
🔷进行下行转换(把基类的指针或引用转换为派生类表示),由于没有动态类型检查,所以是不安全的
class Base {
public:
Base(): b(1) {}
virtual void fun() {}
int b;
};
class Derived: public Base {
public:
Derived(): d(2) {}
int d;
};
int main() {
Base *b1 = new Derived; // 基类指针指向派生类对象
Base *b2 = new Base; // 基类指针指向基类对象
Derived *d1 = static_cast<Derived*>(b1); // 下行转换,安全
cout << d1->d << endl; // 2
Derived *d2 = static_cast<Derived*>(b2); // 下行转换,不安全
cout << d2->d << endl; // 0,基类没有d这个成员,也没报错
return 0;
}
使用:
- 用于基本数据类型之间的转换,如把
int
转换成char
- 把任何类型的表达式转换成
void
类型
任何具有明确定义的类型转换,只要不包括底层const
,都可以使用static_cast
int i = 10, j = 100;
double slope = static_cast<double>(j) / i;
使用static_cast
将void*
指针转换回原来的类型。
// 任何非常量对象的地址都能存入void*
double d = 3.14;
void *p = &d;
double *dp = static_cast<double*>(p);
dynamic_cast
在进行下行转换时,dynamic_cast
具有类型检查(信息在虚函数中)的功能,比static_cast
更安全。转换后必须是类的指针、引用或者void*
,基类要有虚函数,可以交叉转换
dynamic_cast
本身只能用于存在虚函数的父子关系的强制类型转换;对于指针,转换失败则返回nullptr
,对于引用,转换失败会抛出异常
基类没有虚函数,说明没有让基类指针指向子类的必要(不具有多态性),所以使用dynamic_cast
会报错
class A {};
class B : public A {};
int main() {
A *pA = new A;
B *pB = dynamic_cast<B*>(pA); // error: cannot dynamic_cast 'pA' (of type 'class A*') to type 'class B*' (source type is not polymorphic)
return 0;
}
下行转换要转换成功,要求基类指针指向的派生类对象,这样才能把基类指针转换成派生类指针
class Base {
public:
Base(): b(1) {}
virtual void fun() {} // 要有虚函数
int b;
};
class Derived: public Base {
public:
Derived(): d(2) {}
int d;
};
int main() {
Base *b1 = new Derived; // 基类指针指向派生类对象
Base *b2 = new Base; // 基类指针指向基类对象
Derived *d3 = dynamic_cast<Derived*>(b1); // 下行转换成功,等价于static_cast
cout << d3->d << endl; // 2 转换成功
Derived *d4 = dynamic_cast<Derived*>(b2); // 下行转换不成功,返回nullptr
if (d4 == nullptr) {
cout << "d4 is nullptr" << endl; // d4 is nullptr 转换失败
} else {
cout << d4->d << endl;
}
return 0;
}
const_cast
常指针转换为非常指针,并且仍然指向原来的对象。常引用被转换为非常引用,并且仍然指向原来的对象。去掉类型的const
或volatile
属性
int n = 10;
const int *p2 = &n; // 指向常量的指针
int *p3 = const_cast<int*>(p2); // 转换为普通指针
*p3 = 100; // 可以修改指向的对象
cout << *p2 << ", " << *p3 << endl; // 100, 100
reinterpret_cast
- 用于位的简单重新解释
- 允许将任何指针转换为其他指针类型
- 允许将任何整数类型转换为指针类型以及反向转换
- 滥用
reinterpret_cast
可能带来风险,除非所需转换本身是低级别的,否则应使用其他强制转换
int n = 97;
int *p = &n;
char *c1 = reinterpret_cast<char*>(p); // int*指针转换为char*指针
char *c2 = (char*)p;
cout << *c1 << ", " << *c2 << endl; // a, a
类型转换不做检查
class A {
public:
int a;
};
class B {
public:
char b;
};
int main() {
A *pa = new A;
pa->a = 0x12345678;
B *pb = reinterpret_cast<B*>(pa);
cout << pb->b << endl; // 小端存储,对应0x78,也就是120,即'x'
return 0;
}