文章目录




类型转换

C语言类型转换

在C语言里面类型转换比较简单,直接 (转换类型) 类型 强转就可以转换

int a = 10;
//将int类型变量a强转成double类型变量
double b = (double)a;//在这里并没有改变 a 的类型,只是编译器重新解释 a 的类型

C++类型转换

C++类型转换要求更为严格,总共分为四种类型转换运算符

关键字

功能

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 静态类型转换

  • 非const转const、void*转指针
//将基本类型转化成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); 抛出异常