C++四种类型转换总结

来源:微信公众号「编程学习基地」

类型转换

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); 抛出异常

重学感悟

#include <iostream>
#include <memory>
#include <assert.h>
using namespace std;

class Base{
public:
    int num = 5;
    virtual void fun(){
        cout<<"Base fun.."<<endl;
    }
};
class Object:public Base{
public:
    int money = 1000;
    void fun()
    {
        cout << "Object fun.." << endl;
    }
};

int main(int argc, char* argv[])
{
    // static_cast const_cast reinterpret_cast dynamic_cast
    // const_cast 去常属性
    int num = 10;
    const int* pNum = &num;
    int* pNormalNum = const_cast<int*>(pNum);
    *pNormalNum = 20;
    cout<<"num:"<< num << endl;
    // reinterpret_cast 重解析,跟强转区别不大,限制只能转换指针类型,不能对值进行重新解析,只能对指针进行重新解释
    char format = -127;  // 0111 1111 -> 1000 0001
    unsigned char*p = reinterpret_cast<unsigned char*>(&format);
    unsigned char formatNum = (unsigned char)(format);
    printf("formatNum:%d,%d\n",formatNum,*p);

    //static_cast 转常属性 多肽上行转换
    int val = 10;
    const int * ssd = &val; //默认的就可以直接转换  
    const int* tmpVal = static_cast<const int *>(&val);

    Object obj;
    obj.num = 6;
    Base* pBase = &obj;     //子类对象默认转换为基类对象
    // Base *pBase = static_cast<Base *>(&obj);
    cout<< "pBase:" << pBase->num<<endl;

    pBase = dynamic_cast<Base*>(&obj);  //向上造型不检查

    Base base;
    base.num = 1001;
    // Object* pObj = (Object*)&base;   //基类对象不能转换为子类对象,强转可能会出现无法预知的事,不安全,会访问越界
    Object *pObj = static_cast<Object *>(&base);    //不安全,static_cast不做检查
    pObj->fun();
    cout << pObj->money << endl;    //访问了不应该访问的地址,居然没有coredump,神奇

    //dynamic_cast 动态类型转换 用于动态类型转换。只能用于含有虚函数的类,用于类层次间的向上(向上造型不检查)和向下(向下造型借助RTTI检查)转化。
    pObj = dynamic_cast<Object*>(&base);  //向下造型借助RTTI检查,编译通过,对于指针返回NULL 提示警告 warning: dynamic_cast of ‘Base base’ to ‘class Object*’ can never succeed 
    cout<<pObj<<endl;

    return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeRoy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值