• C++的类型转换


    前言

            我们都知道C++是兼容C语言的在C语言中存在两种方式的类型转换,分别是隐式类型转换和显示类型转换(强制类型转换),但是C++觉得C语言的这套东西是够好,所以在兼容C语言的基础上又搞了一套自己的关于类型转换的东西。

    目录

    1.C语言中的类型转换

    2.C++中的类型转换

            3.1static_cast

            3.2reintrepret_cast

            3.3const_cast

            3.4dynamic_cast 

    3.RTTI


    1.C语言中的类型转换

            在C语言中如果赋值运算符的左右两侧值的类型不同,或者形参与实参的类型不匹配,或者返回值类型与接受返回值类型不匹配,就会发生类型转换, C语言中存在两种方式的类型转换,分别是隐式类型转换和显示类型转换(强制类型转换)。

            1.隐式类型转换:编译器在编译的阶段自己进行,能转就转,不能转就会报错,编译失败。一般用于相近的类型

            2.显示类型转换:需要用户自己处理。

             

    1. void Test1()
    2. {
    3. int a = 10;
    4. double b = 2.2;
    5. //隐式类型转换
    6. a = b;
    7. cout << a;
    8. //显示类型转换--强制类型转换
    9. int* p = (int*)a;
    10. cout << p << endl;
    11. }

            缺点:比较暴力,可视性不够好,所有的转换都是以一种形式书写的,难以跟踪错误的转换。 

    2.C++中的类型转换

             所以C++在兼容C语言的基础之上搞出来了自己的一套东西,来对C语言做的不好的地方进行优化,但是这里只是建议使用C++自己的类型转换方式,还是兼容C语言的方式的。

            标准的C++引入了四种命名的强制类型转换符:

            static_cast,reinterpret_cast,const_cast,dynamic_cast.

            3.1static_cast

            statci_cast用于非多态的类型转换,和C语言中的隐式类型转换一样。不能用于两个不相关的类型之间的转换。

    1. void Test2()
    2. {
    3. int a = 10;
    4. double b = 2.3;
    5. a = static_cast<int>(b);//和C语言中的隐式类型转换一致
    6. cout << a;
    7. }

     

            3.2reintrepret_cast

            reinterpret_cast用于两个不想关的类型之间的强制类型转换,与C语言中的强制类型转换大部分是一致的。(除了const类型等的转换)

    1. void Test3()
    2. {
    3. int a = 9;
    4. double* p = nullptr;
    5. p = reinterpret_cast<double*>(a);
    6. cout << p << endl;
    7. }

     

            3.3const_cast

            const_cast最常用的方式就是删除变量的const属性,方便赋值。 

    1. void Test4()
    2. {
    3. const int c = 90;
    4. int* p = const_cast<int*>(&c);
    5. cout << *p << endl;
    6. }

             这里有一个有意思的问题,我们可以一起来看看。

            如果将*p的值改了,c的值会变吗?

    1. void Test4()
    2. {
    3. const int c = 90;
    4. int* p = const_cast<int*>(&c);
    5. cout << *p << endl;
    6. //如果将*p改为10,c的值会变吗?
    7. (*p) = 20;
    8. cout <<"*p = " << *p << endl;
    9. cout<<"c = " << c << endl;
    10. }

            结果是不会改变的,为什么呢?

     

            因为在变量c是const修饰的,所以理论上是不会改变的,所以编译器会对变量c进行处理,将变量c的值存储在寄存器中,虽然*p = 20,确实改变了 变量c的值,但是程序在执行的时候并没有去内存中拿C的值,而是去寄存器中拿c的值所以就会看到这样的结果,实际上是编译器的优化导致的。

            怎么解决这个问题呢?需要对变量加关键字volatile。

    1. void Test4()
    2. {
    3. // const int c = 90;
    4. volatile const int c = 90;
    5. int* p = const_cast<int*>(&c);
    6. cout << "c = " << c << endl;
    7. //如果将*p改为10,c的值会变吗?
    8. (*p) = 20;
    9. cout <<"*p = " << *p << endl;
    10. cout<<"c = " << c << endl;
    11. }

            加上volatile后,程序会去内存中取这个变量的值。 

            3.4dynamic_cast 

            dynamic_cast用于将一个父类的指针/引用转换为子类对象的指针或者引用(动态转换)

            向上转型:子类对象的指针/引用给父类对象的指针/引用的过程(不需要转换,赋值兼容规则),也就是我们常说的切片

            向下转型:父类对象的指针/引用给子类对象的指针/引用的过程(用dynamic_cast进行类型转换是安全的) 。

            注意:

            1.dynamic_cast只能用于父类是多态类的情况,也就是父类必须有虚函数。

            2.dynamic_cast会先检查转换是否成功如果成功则转换,失败则返回0

            

    1. class A
    2. {
    3. public:
    4. virtual void func()
    5. {}
    6. int _a = 10;
    7. };
    8. class B :public A
    9. {
    10. public:
    11. int _b = 20;
    12. };
    13. void Fun(A& a)
    14. {
    15. B *b = (B*)&a;
    16. cout << b->_a << endl << b->_b << endl;
    17. }
    18. int main()
    19. {
    20. A a1;
    21. B b1;
    22. Fun(a1);//如果没有采用dynamic_cast进行动态类型转化这里就会报错,cout打印的是随机值,因为这块空间是不允许被访问的
    23. //Fun(b1);
    24. return 0;
    25. }

             如果没有采用dynamic_cast进行动态类型转化这里就会报错,cout打印的是随机值,因为这块空间是不允许被访问的。

    1. class A
    2. {
    3. public:
    4. virtual void func()
    5. {}
    6. int _a = 10;
    7. };
    8. class B :public A
    9. {
    10. public:
    11. int _b = 20;
    12. };
    13. void FunDynamic(A& a)
    14. {
    15. B* pb = dynamic_cast(&a);
    16. if (pb)//通过返回值进行判断
    17. {
    18. cout << pb->_a << endl << pb->_b << endl;
    19. }
    20. else
    21. {
    22. cout << "类型转换失败!" << endl;
    23. }
    24. }
    25. int main()
    26. {
    27. A a1;
    28. B b1;
    29. FunDynamic(a1);
    30. FunDynamic(b1);
    31. return 0;
    32. }

            dynamic_cast的原理:

            为什么dynamic只能用于父类是多态类的情况呢?这就和dynamic的实现原理有关系了,在虚表上方中有一个位置是专门表示类的类别的,dynamic_cast就是专门去这块空间中取数据判断类的类别,从而区分到底是父类对象还是子类对象,如果是父类对象就会返回0。 这就是为什么要是父类是多态类的原因。

             

    3.RTTI

            RTTI:Run-time Type identification的简称 ,即运行时类型识别。

            C++通过一下方式来支持RTTI:

            1.typeid运算符

            2.dynamic_cast

            3.decltype

  • 相关阅读:
    .NET餐厅管理系统sql数据帮助类执行SQL返回DataReader数据集、执行SQL语句,返回影响的记录数、执行多条SQL语句,实现数据库事务。
    C# 连接 SqlServer 数据库
    网络安全面试题汇总(附答案)
    Qt事件的详细介绍和原理
    【C++】string类的模拟实现
    【开源】SpringBoot框架开发公司货物订单管理系统
    CycGan简单实现后生成图片存在的问题
    【常用图像增强技术,Python-opencv】
    linux环境nacos单击与集群部署
    嵌入式C语言中整形溢出问题分析
  • 原文地址:https://blog.csdn.net/m0_68641696/article/details/132761310