c++ 类型转换

 

========

在 C++ 中,类型转换(type conversion)是将一个数据类型的变量转换为另一个数据类型的变量的过程。类型转换可以分为隐式转换(implicit conversion)和显式转换(explicit conversion)。下面详细介绍 C++ 中的类型转换方式。

隐式转换

隐式转换也称为自动类型转换,是由编译器自动完成的,无需显式指明。这通常发生在以下情况:

  1. 算术运算:当不同类型的变量一起参与算术运算时,编译器会自动将较小类型转换为较大类型。例如,将 int 转换为 float

    cpp
    int a = 5; double b = 6.7; double c = a + b; // a 自动转换为 double 类型
  2. 赋值操作:当将一个类型的值赋给另一个类型的变量时,编译器可能会进行类型转换。

    cpp
    double d = 3.14; int i = d; // d 自动转换为 int,结果为 3(截断小数部分)

显式转换

显式转换是程序员明确指定的类型转换。C++ 提供了几种显式转换的方式:

  1. C 风格转换:

    cpp
    double d = 3.14; int i = (int)d; // C 风格的类型转换
  2. C++ 风格转换:C++ 提供了四种显式类型转换操作符,分别是 static_castdynamic_castconst_castreinterpret_cast

    • static_cast:主要用于良性转换,如基本数据类型之间的转换和类层次结构中基类与派生类之间的指针或引用的转换。

      cpp
      double d = 3.14; int i = static_cast<int>(d); // 使用 static_cast 进行类型转换
    • dynamic_cast:主要用于多态类型转换,即在类层次结构中基类和派生类之间进行安全的向下转换。只能用于包含虚函数的类。

      cpp
      class Base { virtual void func() {} }; class Derived : public Base {}; Base *base = new Derived(); Derived *derived = dynamic_cast<Derived*>(base); // 安全的向下转换
    • const_cast:用于去掉变量的常量性或增加常量性。

      cpp
      const int *p = &i; int *q = const_cast<int*>(p); // 去掉常量性
    • reinterpret_cast:用于任意类型的指针转换,极不安全,一般不推荐使用。

      cpp
      int i = 5; void *p = &i; int *q = reinterpret_cast<int*>(p); // 任意类型的指针转换

总结

C++ 中的类型转换可以分为隐式转换和显式转换。隐式转换由编译器自动完成,而显式转换需要程序员明确指定。显式转换可以通过 C 风格的类型转换和 C++ 风格的类型转换操作符来实现,后者包括 static_castdynamic_castconst_castreinterpret_cast。显式转换操作符更安全、更可读,因此在 C++ 编程中更推荐使用这些操作符。

====================

c语言中我们经常使用类似于 int a =(int)3.14等这种强制类型转换

标准c++的类型转换符:static_cast 、dynamic_cast、 reindivter_cast、 const_cast, 以下分别介绍他们的用法以及举例说明

以下代码编译运行环境:codeblock with gcc in win7(x64)

【1】static_cast 
用法:static_cast < type-id > ( exdivssion ) 

该运算符把exdivssion转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:

①用于类层次结构中基类和子类之间指针或引用的转换。

  进行上行转换(把子类的指针或引用转换成基类表示)是安全的;

  进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。

②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。

③把空指针转换成目标类型的空指针。

④把任何类型的表达式转换成void类型。

注意:static_cast 不能转换掉exdivssion的const、volitale、或者__unaligned属性。

msdn官方解释:http://msdn.microsoft.com/en-us/library/c36yw7x9(v=vs.80).aspx

【2】dynamic_cast

用法:dynamic_cast < type-id > ( exdivssion )

该运算符把exdivssion转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;

如果type-id是类指针类型,那么exdivssion也必须是一个指针,如果type-id是一个引用,那么exdivssion也必须是一个引用。

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。

在类层次间进行上行转换时,dynamic_cast和static_cast 的效果是一样的;

在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast 更安全。

msdn官方解释:http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx

 

举例:下行转换(把基类的指针或引用转换成子类表示)

需要注意的是如果基类中不含虚函数,dynamic_cast 下行转换编译会出错

复制代码
 1 #include<iostream>
 2 using namespace std;
 3 
 4 class father
 5 {
 6 public:
 7     void fun1()
 8     {
 9         cout<<"this is father fun1 call\n";
10     }
11     virtual void fun()
12     {
13         cout<<"this is father fun call\n";
14     }
15 };
16 
17 class son: public father
18 {
19 public:
20     void fun2()
21     {
22         cout<<"this is son fun2 call\n";
23     }
24     void fun()
25     {
26         cout<<"this is the son fun call\n";
27     }
28     int k;
29 };
30 
31 int main()
32 {
33     father *pf, f;
34     son *ps, s;
35 
36     pf = &f;// 基类的指针指向基类对象
37     ps = static_cast<son *>(pf);//这种转换是不安全的,行为是不确定的
38     if(ps != NULL)
39     {
40         ps->fun(); //在本文编译环境下,执行父类的fun
41         //本文编译环境下,一下语句可以执行
42         ps->fun2();
43         ps->k = 1;
44     }
45     ps = dynamic_cast<son *>(pf);//转换后ps = NULL
46     if(ps == NULL)
47         cout<<"dynamic_cast: ps = NULL\n";
48     cout<<"-----------------------------------------------------------------\n";
49     pf = &s; //基类指针开始指向子类对象
50     //此时,两种转换都是安全的
51     ps = static_cast<son *>(pf);
52     if(ps != NULL)
53     {
54         ps->fun();
55         ps->fun2();
56         ps->k = 1;
57     }
58     ps = dynamic_cast<son *>(pf);//转换后ps = NULL
59     if(ps != NULL)
60     {
61         ps->fun();
62         ps->fun2();
63         ps->k = 2;
64     }
65 }
复制代码

结果:

举例:上行转换(把子类的指针或引用转换成基类表示)

复制代码
 1 //类定义同上
 2 int main()
 3 {
 4     father *pf, f;
 5     son *ps, s;
 6 
 7     ps = &s;// 子类的指针指向子类对象
 8     //此时两种转换都是安全的
 9     pf = static_cast<father *>(ps);
10     if(pf != NULL)
11     {
12         pf->fun();
13     }
14     pf = dynamic_cast<father *>(ps);
15     if(pf != NULL)
16     {
17         pf->fun();
18     }
19 
20 }
复制代码

举例: static_cast 用于基本类型之间、基本类型指针和空指针间的转换(不能用于基本类型指针之间转换)。

注意:基本类型由于表示数值范围的不同,因此需要用户保证转换的安全。另外dynamic_cast不能用于此类转换

复制代码
 1 int main()
 2 {
 3     //基本类型间的转换,需要用户保证安全
 4     int a = 1000;
 5     char c = static_cast<char>(a);//不安全,1000超过了char的表示范围
 6     cout<<c<<endl;//输出空
 7     a = 49;
 8     c = static_cast<char>(a);//安全,输出字符‘1’
 9     cout<<c<<endl;
10     //c = dynamic_cast<char>(a); 错误
11     cout<<"-----------------------------------------------------------------\n";
12     //void *和基本类型指针的转换,需要用户保证转换安全
13     a = 49;
14     void *pv;
15     pv = &a;
16     int *pi = static_cast<int *>(pv);//void * 转换为int *
17     cout<<*pi<<endl; //输出49
18     //pi = dynamic_cast<int *>(pv); 错误
19     char *pc = static_cast<char *>(pv);//void *转char*
20     cout<<*pc<<endl;//输出字符‘1’
21     void *pv2 = static_cast<void *>(pc);// char * 转void *
22     cout<<*((char *)pv2)<<endl;////输出字符‘1’
23 }
复制代码

 

【3】reinterpret_cast

用法:reinterpret_cast<type-id> (exdivssion)

reinterpret_cast运算符是用来处理无关类型之间的转换;它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的比特位。按照reinterpret的字面意思“重新解释”,即对数据的比特位重新解释。

IBM的C++指南 里明确告诉了我们reinterpret_cast可以,或者说应该在什么地方用来作为转换运算符:

  • 从指针类型到一个足够大的整数类型
  • 从整数类型或者枚举类型到指针类型
  • 从一个指向函数的指针到另一个不同类型的指向函数的指针
  • 从一个指向对象的指针到另一个不同类型的指向对象的指针
  • 从一个指向类函数成员的指针到另一个指向不同类型的函数成员的指针
  • 从一个指向类数据成员的指针到另一个指向不同类型的数据成员的指针

总结来说:reinterpret_cast用在任意指针(或引用)类型之间的转换;以及指针与足够大的整数类型之间的转换;从整数类型(包括枚举类型)到指针类型,无视大小。

注意:static_cast 不能转换掉exdivssion的const、volitale、或者__unaligned属性。

msdn官方解释:http://msdn.microsoft.com/en-us/library/e0w9f63b(v=vs.80).aspx

举例:reinterpret_cast用法

复制代码
 1 int main()
 2 {
 3    int a = 49;
 4    int *pi = &a;
 5    char *pc = reinterpret_cast<char*>(pi);//int * 到char *,用户自己安全
 6    cout<<*pc<<endl; //输出字符"1"
 7    unsigned long b = reinterpret_cast<unsigned long>(pc);//char * 转 unsigned long
 8    cout<<b<<endl;//输出pc指向地址(即a的地址)对应的整数
 9    int *pi2 = reinterpret_cast<int *>(b);//unsigned long 转 int*
10    cout<<*pi2<<endl; //输出49
11 }
复制代码

【4】const_cast 

用法:const_cast<type-id> (exdivssion)

该运算符用来修改类型的const、volatile、__unaligned属性。除了const 、volatile、__unaligned修饰之外, type_id和exdivssion的类型是一样的。

常量指针被转化成非常量指针,并且仍然指向原来的对象;

常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

msdn官方解释:http://msdn.microsoft.com/en-us/library/bz6at95h(v=vs.80).aspx

举例:const_cast用法

复制代码
1 int main()
2 {
3    const int a = 100;
4    int *b = const_cast<int *>(&a);//const int * 转int *
5    cout<<*b<<endl; //输出100
6    cout<<&a<<" "<<b<<endl; //两者值相同,表明b指向a的地址,只是const属性变了
7 }
复制代码


总结:

类指针或引用的上行转换static_cast 和 dynamic_cast 都可以

类指针或引用的下行转换用dynamic_cast并且判断转换后是否为空

基本数据类型之间的转换用static_cast, 但是由于数值范围的不同,需要用户保证转换的安全性

不同类型之间的指针或引用的转换用reinterpret_cast,它的本质是对指向内存的比特位的重解释

消除数据的const、volatile、__unaligned属性,用const_cast

【版权声明】转载请注明出处 http://www.cnblogs.com/TenosDoIt/p/3175217.html

 

=======

 

参考:

https://www.cnblogs.com/TenosDoIt/p/3175217.html

posted @ 2024-05-28 12:00  redrobot  阅读(234)  评论(0编辑  收藏  举报