c++中的类型转换

Posted MaxBruce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\\n", k);  // 5
27     printf("j = %d\\n", j);  // 5
28     
29     y = 8;
30     
31     printf("x = %d\\n", x);  // 2
32     printf("y = %d\\n", y);  // 8
33     printf("&x = %p\\n", &x);// 0x7fffd40b84e8
34     printf("&y = %p\\n", &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 }
复制代码

 

复制代码
 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 测试案列 》可知,当使用 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_cast 与 dynamic_cast 的使用情况还可以查阅另一篇博客 《 c++中的类型识别 》中的 如何实现动态类型 这一节。

类型转换函数

1、转换构造函数

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

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

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

  转换方式

  1. static_ cast<ClassName >(value);

  2. ClassName(value);

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

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

         

 转换构造函数之 基本类型 -> 类类型

 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 */
复制代码

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

           

以上是关于c++中的类型转换的主要内容,如果未能解决你的问题,请参考以下文章

使用 C++ 反转句子中的每个单词需要对我的代码片段进行代码优化

从类名转换的 C++ 指针类型 [关闭]

C++ 或 Java 中的类型转换和类型转换有啥区别?

如何将 System::^array 从 C# 函数转换为 C++ 中的等效数据类型

c++中的类型转换

C++中的类型转换函数