首页 > 编程语言 >c++ 类型转换

c++ 类型转换

时间:2024-05-28 12:12:05浏览次数:25  
标签:类型转换 ps 转换 int c++ cast 类型 指针

 

========

在 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

标签:类型转换,ps,转换,int,c++,cast,类型,指针
From: https://www.cnblogs.com/rebrobot/p/18217652

相关文章

  • c++动态内存管理干货
     c++兼容c所以之前C语言使用的方式在c++中同样可以使用,但c++给出了更加简便的动态内存管理方法.1.申请内置类型空间c++定义了新的关键字new和delete(都是操作符不是函数),使用方法如图:需要注意的是,用new申请空间默认不会初始化,但是可以初始化。如图:另外,【】里面可以是变量:......
  • C++ - TCP粘包解决方法
     下面的代码演示了粘包问题,客户端连续三次向服务器端发送数据,服务器端却一次性接收到所有数据。服务器代码#define_WINSOCK_DEPRECATED_NO_WARNINGS#include<iostream>usingnamespacestd;//#include<stdio.h>#include<WinSock2.h>​//#pragmacomment(lib,"ws2_......
  • C++中的异类:“#” 符号背后的故事
    最近在写编程语言的书,聊到C++的宏,感觉很有意思,搬运过来。在C++语言中,# 符号是一个独特的符号。它似乎不在语言核心中,但是在源码里却又无处不在。在语法上,#的语法规则在C++体系里独具一格,和C++语法相比像是两个语言似的。这些差别让我们感受到#背后的故事不简单。今天,我们......
  • c++函数指针
     c/c++函数指针的用法【目录】基本定义c函数指针使用举例c++函数指针使用举例函数指针作为函数参数函数指针作为函数返回值函数指针数组typedef简化函数指针操作 c语言函数指针的定义形式:返回类型 (*函数指针名称)(参数类型,参数类型,参数类型,…);c++函数指针......
  • lambda表达式的用例 c++
    出自:  https://blog.csdn.net/qq_45604814/article/details/132687858一、Lambda表达式概述1.介绍Lambda表达式是C++11标准引入的一种特性,它提供了一种方便的方式来定义匿名函数。Lambda表达式是一种能够捕捉外部变量并使用它们的函数对象。由捕获列表、参数列表、返......
  • 打开编程世界 跟着Mr.狠人一起学C/C++
    打开编程世界跟着Mr.狠人一起学C/C++自我介绍大家好,我是Mr.狠人。我高中就读于墨尔本,学习的方向是会计,因为疫情我回到国内读大学,大学的专业是国贸,可以说我没有任何的计算机基础。但我在海外研究生阶段毅然决然的选择了计算机专业,我本可以选择金融专业,或是更简单的管理专业......
  • C++ ─── string的模拟实现
            本博客将简单实现来模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。    下期我们继续讲解完整版string的模拟实现(将不再会是浅拷贝了)        说明:下述string类没有显式定义其拷贝构造函数与赋值运......
  • A Simple Problem with Integers(C++)
     【题目描述】这是一道模板题。给定数列 a[1],a[2],…,a[n] ,你需要依次进行q 个操作,操作有两类:C、lrx :给定 l,r,x ,对于所有 i∈[l,r] ,将 a[i] 加上 x (换言之,将 a[l],a[l+1],…,a[r] 分别加上 x );Q、lr :给定l,r ,求 ∑ri=la[i] 的值(换言之,求 a[l]+a[l+......
  • c++设计模式-装饰器模式和代理模式
    namespace_nmsp1{//抽象的控件类classControl{public:virtualvoiddraw()=0;//draw方法,用于将自身绘制到屏幕上。public:virtual~Control(){}//做父类时析构函数应该为虚函数};//列表控件类classListCtrl......
  • 【C++】旋转字符串——精准与否,就是屠宰和手术的区别
    ✨题目链接:NC114旋转字符串✨题目描述 字符串旋转:给定两字符串A和B,如果能将A从中间某个位置分割为左右两部分字符串(可以为空串),并将左边的字符串移动到右边字符串后面组成新的字符串可以变为字符串B时返回true。例如:如果A=‘youzan’,B=‘zanyou’,A按‘you’‘zan’......