zoukankan      html  css  js  c++  java
  • c++中的类型转换

    目录

      1. 隐式类型转换

      2. 强制类型转换( static_castconst_castreinterpret_castdynamic_cast

      3. 类型转换函数、转换构造函数

      类型转换可分为 隐式类型转换(编译器自动完成) 与 强制类型转换(需要自己操作)。

    隐式类型转换  

      基本数据类型之间会进行隐式的类型安全转换。其转换规则如下:

      

       我们用 1个案列来介绍这种隐式类型转换规则,会有意想不到的结果发生....!!!

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 int main()
     7 {   
     8     short s = 'a';
     9     unsigned int ui = 1000;
    10     int i = -2000;
    11     double d = i;
    12     
    13     cout << "d = " << d << endl;
    14     cout << "ui = " << ui << endl;
    15     cout << "ui + i = " << ui + i << endl;
    16     
    17     if( (ui + i) > 0 )  // 变量i会进行隐式类型转换 -> unsigned int  // ui + i > 0
    18     {
    19         cout << "Positive" << endl;
    20     }
    21     else
    22     {
    23         cout << "Negative" << endl;
    24     }
    25     
    26     cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl;    // 4 // s -> int  'b' -> int // sizeof(s + 'b') = sizeof(int) // 编译器默认是int运算
    27     
    28     return 0;
    29 }
    30 /*
    31     d = -2000
    32     ui = 1000
    33     ui + i = 4294966296
    34     Positive
    35     sizeof(s + 'b') = 4
    36 */
    基本类型的隐式类型转换案列

      在c++中,还有其它几种隐式类型转换(后续讲解),那么现在试想一下这几个问题:

        1. 基本类型 可以转换为 类类型吗?--- 可以,见转换构造函数;

        2. 类类型 可以转换为 基本类型吗?--- 可以,见类型转换函数;

        3. 类类型之间可以转换吗?--- 可以,见转换构造函数 和 类型转换函数;

      注:这种隐式类型转换不能够抑制,并且也是bug的来源之一;

    强制类型转换

      在介绍c++强制类型转换前,我们可以回顾一下c语言中的强制类型转换。c语言中的强制类型转换十分简单、粗暴,即 (Type)(Expression);或者 Type(Expression);但是,这种简单的强制类型转换引发了很多问题,可归纳为如下2点:

      1. 任意类型之间都可以进行转换,编译器很难判断其正确性(过于粗暴);

      2. 在源码中无法快速定位所有使用强制类型转换的语句(很难定位);

    所以,基于这2点考虑,在c++中引入了新式类型转换( static_castconst_castreinterpret_castdynamic_cast),其使用方法可归纳为 xxx_cast<Type>(Expression)

    1、static_cast

      1. 用于 基本类型间的转换

      2. 不能用于基本类型指针间的转换

      3. 用于有继承关系类对象之间的转换和类指针之间的转换

      4. 用于 其它类型(基本类型和类类型) 向 类类型之间的转换;static_cast<类类型>(其它类型),见转换构造函数。

    2、 const_cast

      1. 用于去除变量的只读属性

      2. 强制转换的目标类型必须是指针或引用

    3、 reinterpret_cast

      1. 用于指针类型间的强制转换

      2. 用于整数和指针类型间的强制转换

    4、 dynamic_cast

      1. 用于有继承关系的类指针(引用)间的转换

      2. 用于有交叉关系的类指针(引用)间的转换

      3. 相关类(基类)中必须有虚函数的支持

      4. 具有类型检查的功能,但类型转换的结果只可能在运行阶段得到;

      指针转换:

        转换成功:得到目标类型的指针;

        转换失败:得到一个空指针;

      引用转换: 

        转换成功:得到目标类型的引用;

        转换失败:得到一个异常操作的信息;

      dynamic_cast 转换时错误提示:

        1. 不能将父类指针 直接 转换为 子类指针

          

            

         2. 在 父类中没有虚函数,不能发生多态 polymorphic

          

           

     1 #include <stdio.h>
     2 
     3 void static_cast_demo()
     4 {
     5     int i = 0x12345;
     6     char c = 'c';
     7     int* pi = &i;
     8     char* pc = &c;
     9     
    10     c = static_cast<char>(i);
    11     pc = static_cast<char*>(pi);    // error static_cast 不能用于基本类型指针之间 的转换
    12 }
    13 
    14 void const_cast_demo()
    15 {
    16     const int& j = 1;
    17     int& k = const_cast<int&>(j);
    18     
    19     const int x = 2;
    20     int& y = const_cast<int&>(x);
    21     
    22     int z = const_cast<int>(x);     // error const_cast 强制转换的目标类型必须是指针或引用类型
    23     
    24     k = 5;
    25     
    26     printf("k = %d
    ", k);  // 5
    27     printf("j = %d
    ", j);  // 5
    28     
    29     y = 8;
    30     
    31     printf("x = %d
    ", x);  // 2
    32     printf("y = %d
    ", y);  // 8
    33     printf("&x = %p
    ", &x);// 0x7fffd40b84e8
    34     printf("&y = %p
    ", &y);// 0x7fffd40b84e8
    35 }
    36 
    37 void reinterpret_cast_demo()
    38 {
    39     int i = 0;
    40     char c = 'c';
    41     int* pi = &i;
    42     char* pc = &c;
    43     
    44     pc = reinterpret_cast<char*>(pi);
    45     pi = reinterpret_cast<int*>(pc);
    46     pi = reinterpret_cast<int*>(i);
    47     c = reinterpret_cast<char>(i);  // error reinterpret_cast 适用于指针类型之间的转换  和 整型与指针类型之间的转换
    48 }
    49 
    50 void dynamic_cast_demo()
    51 {
    52     int i = 0;
    53     int* pi = &i;
    54     char* pc = dynamic_cast<char*>(pi); // error
    55 }
    56 
    57 int main()
    58 {
    59     static_cast_demo();
    60     const_cast_demo();
    61     reinterpret_cast_demo();
    62     dynamic_cast_demo();
    63     
    64     return 0;
    65 }
    static_cast、const_cast、reinterpret_cast、dynamic_cast 初体验
     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 class Base
     7 {
     8 public:
     9     Base()
    10     {
    11         cout << "Base::Base()" << endl;
    12     }
    13     
    14     virtual ~Base()
    15     {
    16         cout << "Base::~Base()" << endl;
    17     }
    18 };
    19 
    20 class Derived : public Base
    21 {
    22 public:
    23     Derived()
    24     {
    25         cout << "Derived::Derived()" << endl;
    26     }
    27     
    28     void func()
    29     {
    30         cout << "Derived::func()" << endl;
    31     }
    32     
    33     virtual ~Derived()
    34     {
    35         cout << "Derived::~Derived()" << endl;
    36     }
    37 };
    38 
    39 void test1()
    40 {
    41     Base* bp = new Derived();
    42     
    43     Derived *dp = dynamic_cast<Derived*>(bp);   // 当父类指针指向的是子类对象,转换成功
    44     //Derived *dp = static_cast<Derived*>(bp);  // 当父类指针指向的是子类对象,转换成功
    45     if( dp != NULL )
    46     {
    47         cout << "dp = " << dp << endl;
    48         dp->func();
    49     }
    50     else
    51     {
    52         cout << "Cast error!" << endl;
    53     }
    54     
    55     delete bp;
    56 }
    57 
    58 void test2()
    59 {
    60     Base* bp = new Base();
    61     
    62     Derived *dp = dynamic_cast<Derived*>(bp);   // 转化失败,不能将父类指针对象转换为子类指针对象
    63     //Derived *dp = static_cast<Derived*>(bp);     // 转换成功,可以将父类指针对象转换为子类指针对象,但可能有 Bug 存在
    64     if( dp != NULL )
    65     {
    66         cout << "dp = " << dp << endl;
    67         dp->func();
    68     }
    69     else
    70     {
    71         cout << "Cast error!" << endl;
    72     }
    73     
    74     delete bp;
    75 }
    76 
    77 int main()
    78 {
    79     test1();
    80     
    81     cout << "-----------------------" << endl;
    82     
    83     test2();
    84 
    85     return 0;
    86 }
    static_cast 与 dynamic_cast 测试案列

      通过 《 static_cast 与 dynamic_cast 测试案列 》可知,当使用 dynamic_cast 强制类型转换时,即 Derived *dp = dynamic_cast<Derived*>(bp); 程序的运行结果为:

              

       当使用 static_cast 强制类型转换时,即 Derived *dp = static_cast<Derived*>(bp); 程序的运行结果为:

             

      从运行结果可知, static_cast 与 dynamic_cast 在继承中进行类指针转换时是存在差异的;其中,

        1. 相同点:当父类指针 指向 子类对象时,二者都可以将父类指针 成功转换为 子类指针;

          

         2. 不同点:当父类指针 指向 父类对象时,

          1) static_cast 转换:可以将父类指针 成功转换为 子类指针;

          2)dynamic_cast 转换:父类指针 不能够转换为  子类指针;

           

      对于 static_castdynamic_cast 的使用情况还可以查阅另一篇博客 《 c++中的类型识别 》中的 如何实现动态类型 这一节。

    类型转换函数

    1、转换构造函数

      当构造函数只有1个参数 参数的类型是基本类型 或者是 其它类型时,就是转换构造函数。其作用是将其他类型 转换为 类类型

      编译器尽力尝试的结果是隐式类型转换,隐式类型转换是工程中bug的重要来源;

      工程中通过explicit关键字杜绝隐式转换,转换构造函数被explicit修饰时只能进行显示转换;

      转换方式

      1. static_ cast<ClassName >(value);

      2. ClassName(value);

      3. (ClassName)value; //不推荐

      在类型转换时调用转换构造函数。

             

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 class Test
     7 {
     8     int mValue;
     9 public:
    10     Test()
    11     {
    12         mValue = 0;
    13     }
    14     
    15     explicit Test(int i)
    16     {
    17         mValue = i;
    18     }
    19     
    20     Test operator + (const Test& p)
    21     {
    22         Test ret(mValue + p.mValue);
    23         
    24         return ret;
    25     }
    26     
    27     int value()
    28     {
    29         return mValue;
    30     }
    31 };
    32 
    33 int main()
    34 {   
    35     Test t;
    36     Test r;
    37     
    38     // 隐式类型转换 不加explicit关键字
    39     //t = 5;        // t = Test(5);
    40     //r = t + 10;   // r = t + Test(10);
    41     
    42     t = static_cast<Test>(5);    // t = Test(5);    
    43     r = t + static_cast<Test>(10);   // r = t + Test(10);
    44     
    45     cout << r.value() << endl;  // 15
    46     
    47     return 0;
    48 }
    转换构造函数之 基本类型 -> 类类型

     2、类型转换函数

       c++ 中可以定义类型转换函数,其作用是将 类类型 转换为 其它类型;其语法格式为:

    1 // 类型转换函数语法格式
    2 operator Type()
    3 {
    4      Type ret;
    5 
    6      // ...
    7   
    8      retuan Type;
    9 }

      编译器能够隐式的使用类型转换函数

     

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 class Test
     7 {
     8     int mValue;
     9 public:
    10     Test(int i = 0)
    11     {
    12         mValue = i;
    13     }
    14     int value()
    15     {
    16         return mValue;
    17     }
    18     operator int ()
    19     {
    20         return mValue;
    21     }
    22 };
    23 
    24 int main()
    25 {   
    26     Test t(100);
    27     int i = t;  // 隐式的使用类型转换函数 operator int ()
    28     
    29     cout << "t.value() = " << t.value() << endl;    // t.value() = 100
    30     cout << "i = " << i << endl;    // i = 100
    31     
    32     return 0;
    33 }
    类型转换函数之 类类型 -> 基本类型

    3、类型转换函数  VS  转换构造函数 

      结论:

      1. 类型转换函数 与 转换构造函数 具有同等的地位

      2. 无法抑制隐式的类型转换函数调用,此时 类型转换函数可能与转换构造函数冲突(类类型之间的转换);

      3. 在类型转换时 调用类型转换函数 、转换构造函数。

      4. 工程中以Type toType()的公有成员 代替 类型转换函数

        

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 class Test;
     7 
     8 class Value
     9 {
    10 public:
    11     Value()
    12     {
    13     }
    14     explicit Value(Test& t)
    15     {
    16         cout << "explicit Value(Test& t)" << endl;
    17     }
    18 };
    19 
    20 class Test
    21 {
    22     int mValue;
    23 public:
    24     Test(int i = 0)
    25     {
    26         mValue = i;
    27     }
    28     int value()
    29     {
    30         return mValue;
    31     }
    32     operator Value()
    33     {
    34         Value ret;
    35         cout << "operator Value()" << endl;
    36         return ret;
    37     }
    38 };
    39 
    40 int main()
    41 {   
    42     Test t(100);
    43     Value v1 = t;    // 隐式的调用类型转换函数 operator Value()
    44     Value v2 = static_cast<Value>(t);    // 显示的调用转换构造函数 explicit Value(Test& t)
    45     
    46     return 0;
    47 }
    48 /*
    49     运行结果:
    50     operator Value()
    51     explicit Value(Test& t)
    52 */
    类类型之间的相互转换

          //  类型转换函数与转换构造函数发生冲突   的示意图    

               

  • 相关阅读:
    access denied for user 'root'@'localhost'(using password:YES) FOR WINDOWS
    PKU 1001解题代码
    PKU 1002解题总结
    为什么vue组件data必须是函数
    call 和 apply 区别
    CSS|Stacking context 堆叠上下文
    Vue3.0 tsx 函数组件
    js中的变量提升
    JavaEE|架构
    MVC,MVP 和 MVVM
  • 原文地址:https://www.cnblogs.com/nbk-zyc/p/12383810.html
Copyright © 2011-2022 走看看