类型转换
C语言类型转换
在C语言里面类型转换比较简单,直接 (转换类型) 类型 强转就可以转换
int a = 10;
//将int类型变量a强转成double类型变量
double b = (double)a;//在这里并没有改变 a 的类型,只是编译器重新解释 a 的类型 C++类型转换
C++类型转换要求更为严格,总共分为四种类型转换运算符
[tr]关键字功能[/tr]const_cast | 去常属性 | reinterpret_cast | 重解释类型转换 | static_cast | 静态类型转换 | dynamic_cast | 动态类型转换 | 统一使用规范:关键字 (expression)
const_cast 去常属性
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,英文翻译:易变的; 无定性的;其实就是告诉编译器这个关键字修饰的变量不安全,你要到内存里面去操作,不要优化
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重解释
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 static_cast 静态类型转换
//将基本类型转化成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);//向下造型 下行转换 不安全 dynamic_cast 动态类型转换
- 用于动态类型转换。只能用于含有虚函数的类,用于类层次间的向上(向上造型不检查)和向下(向下造型借助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); 抛出异常
|