在C语言里面类型转换比较简单,直接 (转换类型) 类型 强转就可以转换
int a = 10; //将int类型变量a强转成double类型变量 double b = (double)a;//在这里并没有改变 a 的类型,只是编译器重新解释 a 的类型
C++类型转换要求更为严格,总共分为四种类型转换运算符
关键字 | 功能 |
---|---|
const_cast | 去常属性 |
reinterpret_cast | 重解释类型转换 |
static_cast | 静态类型转换 |
dynamic_cast | 动态类型转换 |
统一使用规范:关键字 (expression)
const_cast<转换类型>(变量);
#include<iostream> using namespace std; int main() { int temp = 49; const int * p1 = &temp; //不能通过指针修改指针指向的值 int* p2, *p3; /***C类型转换***/ p2 = (int*)p1; *p2 = 10; cout << *p2 << endl; /***C++类型转换***/ p3 = const_cast<int*>(p1); //去常属性 *p3 = 20; cout << *p3 << endl; return 0; } 打印结果 10 20
在去常属性里面还有个有趣的现象
#include<iostream> using namespace std; int main() { int const tmp = 100; //定义常量tmp tmp不能修改 int const* p = &tmp; //不能通过指针修改指向的值 int* const q = const_cast<int*>(p); //去常属性 可以通过指针修改指向的内容 *q = 200; cout << tmp << " " << *p << " " << *q << endl; //打印变量的值 cout << &tmp << endl << p << endl << q << endl; //打印变量地址 return 0; } 打印结果 100 200 200 0086F9D0 0086F9D0 0086F9D0
what?什么,地址一样,打印结果不一样,不是应该一样的吗!!!
既然标题是寄存器骚操作,那原因肯定和寄存器有关
这个其实是编译器的一个优化,当定义常量时
int const tmp = 100; //定义常量tmp tmp不能修改
我们就相当于和编译器约定好了,我们不会去修改tmp的值,这个时候编译器就会做一个优化,将tmp的值,放到寄存器里面,然后读取tmp时直接在寄存器里面读取,加快读取速度。
这个时候我们有去常属性const_cast,动过变量q修改tmp在内存中的值
*q = 200;
在打印结果时,tmp读取的是寄存器的值,p ,q读取的是内存的值
cout << tmp << " " << *p << " " << *q << endl; //打印变量的值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5BvhScSY-1624967855258)(D:\微信公众号\Typora\C++\类型转换\寄存器.png)]
上面这种优化肯定要不得,所以有一个关键字来解决这种不好的优化问题,那就是volatile,英文翻译:易变的; 无定性的;其实就是告诉编译器这个关键字修饰的变量不安全,你要到内存里面去操作,不要优化
volatile int const tmp2 = 100; volatile int const* pm = &tmp2; //不能通过指针修改指向的值 int* const qm = const_cast<int*>(pm); //q本身只读 指向读写 *qm = 200; cout << tmp2 << " " << *pm << " " << *qm << endl; cout << (void*)&tmp2 << endl << (void*)pm << endl << qm << endl; 打印结果: 200 200 200 007CFDDC 007CFDDC 007CFDDC
这样就不会出现地址一样,数值不一样的情况了
reinterpret_cast运算符用于天生危险的类型转换,它不允许删除const,用法和const_cast一样:<reinterpret_cast>(转换类型)
其实和强转并没有什么太大的区别,用个例子来简单说明下
#include<iostream> using namespace std; int main() { int* pi = new int(10); //double* pd = pi; int* 不能直接转换成 double* /***C++类型转换***/ double* pd = reinterpret_cast<double*>(pi); /***C类型转换***/ //double* pd = (double*)pi; cout << *pi << " " << *pd << endl; //将整型重新解释为指针 int addr = 0x12345678; // 78 56 34 12 char* pc = reinterpret_cast<char*>(&addr); for (int i = 0; i<4; ++i) { cout << showbase << hex << (int)*(pc + i) << " "; } return 0; } 打印结果: 10 -7.84591e+298 0x78 0x56 0x34 0x12
//将基本类型转化成void类型指针 double num = 12.12; void* vp = static_cast<void*>(&num); const double* cnum = static_cast<const double*>(vp); cout << typeid(*cnum).name() << endl;
有四个类Base,Parent,Chile,Other,继承关系如下
class Base { public: virtual void foo(){ cout << "Base::foo" << endl; } int m_a{ 5 }; }; class Parent :public Base { public: void foo(){ cout << "Parent::foo" << endl; } int m_b{ 10 }; }; class Child :public Parent { public: void foo(){ cout << "Chile::foo" << endl; } }; class Other { public: void foo(){ cout << "Other::foo" << endl; } };
向上造型 上行转换 安全
Parent b; Base* pa = static_cast<Base*>(&b); //基类指针指向子类对象 向上造型 上行转换 安全 pa->foo(); //由多肽性质可知调用的是Parent::foo
向下造型 下行转换 不安全 不允许出现下面情况
Base a; Parent* pb = static_cast<Parent*>(&a);//向下造型 下行转换 不安全
用于动态类型转换。只能用于含有虚函数的类,用于类层次间的向上(向上造型不检查)和向下(向下造型借助RTTI检查)转化。
只能转指针或引用
向下转化时,如果是非法的对于指针返回NULL,对于引用抛bad_cast异常
RTTI 运行时类型识别
RTTI只能用于包含虚函数的类
Parent p; Child* pc = static_cast<Child*>(&p); cout << "chile:" << pc << endl; Child *pcc = dynamic_cast<Child*>(&p); cout << "chile:" << pcc << endl; //Child &pccc = dynamic_cast<Child&>(&p); 抛出异常