c++强制类型转换分为四种,static_cast
,dynamic_cast
,const_cast
,reinterpret_cast
一.为什么在C++中还有特殊的四种强制转换
- 因为C风格的强制类型转换,在C++中可能带来一些隐患,难以察觉.(可以在任意类型之间进行转换),使用c++的强制类型转换可以让语义更加明确,提高类型安全性.
二.static_cast
- static_cast 作用和C风格的强制类型转换的效果基本一样,在运行的时候没有类型检查来保证转换的安全性
- 用于基本数据类型之间的转换,如int -> char
- static_cast 并不能转换原有类型的const ,volatile限制
#include < iostream>
int main()
{
float f = 3.14;
int i = static_cast<int>(f);
std::cout << i << std::endl;
}
三.const_cast
- const_cast 用于强制去掉不能被修改的常数特性,但是需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或者引用的常量性,并且去除常量性的对象必须为指针或者引用.
- 一般用于去除类型的const 属性和volatile 属性
#include < iostream>
int main()
{
const int i = 2;
const int * p = &i;
auto q = const_cast<int* > (p);
*q = 20;//未定义行为,由编译器来进行实现
std::cout << i << std::endl; // 2
std::cout << *q << std::endl; //*q
return 0;
}
- 从输出结果来看 i 依然是 2 , *q 的值被改变。我理解的是const int 变量被放入到寄存器中优化,*q 只是修改了内存中的值,我们可以通过添加volatitle来进行实验.
- 我们应该避免去使用const_cast
四.reinterpret_cast
- 通常用于指针类型的转换
- 改变指针或者引用的类型
- 将整形转换为指针或者引用类型
- 将指针或引用转换为一个足够长度的整形
- 用法:
reinterpret_cast<type_id>(expression)
- type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。在使用reinterpret_cast强制转换过程仅仅只是比特位的拷贝,因此在使用过程中需要特别谨慎!
#include< iostream>
#include< cstdint>
using namespace std;
int main() {
int *ptr = new int(233);
auto ptr_addr = reinterpret_cast<double *>(ptr);
std::cout << ptr << std::endl;
std::cout << ptr_addr << std::endl;
delete ptr;
return 0;
}
四.dynamic_cast
用法:dynamic_cast<type_id> (expression)
(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话,如果是指针返回nullptr,如果是引用抛出异常
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。
(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
向上转换,即为子类指针指向父类指针(一般不会出问题);向下转换,即将父类指针转化子类指针。
向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Base{
public:
Base() :str(nullptr){}
Base(string s) :str(s){}
virtual void print()
{
cout << str << " ";
}
private:
string str;
};
class Derived:public Base
{
public:
Derived(){}
Derived(string s,int i) :Base(s),ival(i){}
void print()
{
Base::print();
cout << ival << endl;
}
void print_ival()
{
cout << "仅输出ival的值:" << ival << endl;
}
private:
int ival;
};
int main()
{
Base base("aaa");
Derived de("xxx", 111);
//指针dynamic_cast
Base* pb = &de;
if (Derived* pd = dynamic_cast<Derived*>(pb))
{
pd->print();
}
else
{
//转换失败返回空指针
cout << "type error..." << endl;
}
//引用dynamic_cast
Base& rf = de;
try
{
Derived& d = dynamic_cast<Derived&>(rf);
d.print_ival();
}
catch (const std::bad_cast& ex)
{
//转换失败,抛出std::bad_cast异常
cout << ex.what();
}
return 0;
}