文章目录

  • 1 隐式类型转换
    • 1.1 隐式类型转换的基本概念
    • 1.2 隐式类型转换的发生点
    • 1.3 浮点数赋值给整形数分析
  • 2 C语言中的强制类型转换
  • 3 C++中的强制类型转换
    • 3.1 static_cast
    • 3.2 const_cast
    • 3.3 reinterpret_cast
    • 3.4 dynamic_cast
    • 3.5 类型转换使用建议

C/C++语言中的数据类型转换主要有两种:强制类型转换和隐式类型转换。

1 隐式类型转换

1.1 隐式类型转换的基本概念

我们首先需要知道,隐式类型转换是编译器主动进行的类型转换。

对于隐式数据类型转换来说:

  • 低类型到高类型的隐式类型转换是安全的,不会产生截断。
  • 高类型到低类型的隐式类型转换是不安全的,导致不正确的结果。
  • 比如:浮点数赋值给整形时,会发生截断(小数部分丢失)。

注意: 标准C编译器的类型检查是比较宽松的,因此隐式类型转换可能带来意外的错误。

1.2 隐式类型转换的发生点

隐式类型转换的发生点如下:

  • 算术运算式中,低类型转换为高类型。
  • 赋值表达式中,表达式的值转换为左边变量的类型。
  • 函数调用时,实参转换为形参的类型。
  • 函数返回值,return表达式转换为返回值类型。

安全的隐式类型转换:

1.3 浮点数赋值给整形数分析

直接赋值:

可以看到,编译器直接将浮点数截断。

通过函数调用:


可以看到,函数调用时也是发生了隐式类型转换,编译器直接将浮点数进行截断。

注意:当使用如下语句时printf("%d\n", 3.14);,将得到错误的结果。由于是变参,所以编译器根本不知道是什么类型,不会进行隐式类型转换。


2 C语言中的强制类型转换

强制类型转换的语法:

  • (Type)var_name;
  • (Type)value;

强制类型转换的结果:

  • 目标类型能够容纳目标值,结果不变。
  • 目标类型不能容纳目标值:结果将产生截断。
  • 注意:不是所有的强制类型转换都能成功,当不能进行强制类型转换时,编译器将产生错误信息。

3 C++中的强制类型转换

C 方式强制类型转换存在的问题:

  • 过于粗暴:任意类型之间都可以进行转换,编译器很难判断其正确性。
  • 难于定位 :在源码中无法快速定位所有使用强制类型转换的语句。

问题:强制类型转换在实际工程中是很难完全避免的!如何进行更加安全可靠的转换?

C++ 将强制类型转换分为4种不同的类型: static_cast、const_cast、dynamic_cast、reinterpret_cast。

用法:xxx_cast(Expression)

3.1 static_cast

static_cast强制类型转换:

  • 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。上行指针或引用(派生类到基类)转换安全,下行不安全。
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
  • 把空指针转换成目标类型的空指针。
  • 把任何类型的表达式转换成void指针类型。
#include <iostream>using namespace std;class Animal {public:virtual void cry() = 0;
};class Cat :public Animal
{public:void cry(){cout << "喵喵瞄" << endl;}};class Dog :public Animal
{public:void cry(){cout << "汪汪汪" << endl;}};int main(void) {//第一种情况  父子类之间的类型转换Dog* dog1 = new Dog();Animal* a1 = static_cast<Animal*>(dog1); //子类的指针转型到父类指针Dog* dog1_1 = static_cast<Dog*>(a1);     //父类的指针转型到子类的指针Cat* cat1 = static_cast<Cat*>(a1);       //父子到子类,有风险,这样时不行的,会出问题,但是我们如果去调用cat1相关的函数时,不管是不是虚函数都是Cat类的函数,这就是静态连编。如果两者之间的内存结构不同,则可能会出错。Dog dog2;Animal& a2 = static_cast<Animal&>(dog2); //子类的引用转型到父类的引用Dog &dog2_2 = static_cast<Dog&>(a2);     //父类到子类引用//第二种 基本类型的转换int  kk = 234;char cc = static_cast<char>(kk);//第三种 把空指针转换成目标类型的空指针。int* p = static_cast<int*>(NULL);Dog* dp = static_cast<Dog*>(NULL);//第四种 把任何类型的表达式转换成void类型int* pi = new int[10];void* vp = static_cast<void*>(pi);vp = pi;system("pause");return 0;
}

3.2 const_cast

const_cast强制类型转换:

  • 用于去除变量的只读属性。
  • 强制转换的目标类型必须是指针或引用。
void const_cast_demo()
{const int& j = 1;int& k = const_cast<int&>(j);const int x = 2;    //真正意义上的常量int& y = const_cast<int&>(x);//编译器会为x分配空间,y指向的是为x分配的空间int z = const_cast<int>(x); //errork = 5;printf("k = %d\n", k);printf("j = %d\n", j);y = 8;printf("x = %d\n", x);printf("y = %d\n", y);printf("&x = %p\n", &x);printf("&y = %p\n", &y);
}/*
k = 5
j = 5
x = 2
y = 8
*/

3.3 reinterpret_cast

reinterpret_cast强制类型转换:

  • 用于指针类型间的强制转换。
  • 用于整数和指针类型间的强制转换。
  • 引用之间的转换。

目标类型必须是一个指针、引用、算术类型、函数指针!

忠告:滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。

#include <iostream>using namespace std;class Animal {public:void cry() {cout << "动物叫" << endl;}
};class Cat :public Animal
{public:void cry(){cout << "喵喵瞄" << endl;}};class Dog :public Animal
{public:void cry(){cout << "汪汪汪" << endl;}};int main(void) {//用法一   数值与指针之间的转换int* p = reinterpret_cast<int*>(0x99999);int val = reinterpret_cast<int>(p);//用法二  不同类型指针和引用之间的转换Dog  dog1;Animal* a1 = &dog1;a1->cry();Dog* dog1_p = reinterpret_cast<Dog*>(a1);Dog* dog2_p = static_cast<Dog*>(a1);   //如果能用static_cast ,static_cast 优先//Cat* cat1_p = static_cast<Cat*>(a1);//Cat* cat2_p = static_cast<Cat*>(dog1_p);//NO! 不同类型指针转换不能使用static_castCat* cat2_p = reinterpret_cast<Cat*>(dog1_p);Animal& a2 = dog1;Dog& dog3 = reinterpret_cast<Dog&>(a2);//引用强转用法,不同类型之间的引用也可以转换dog1_p->cry();dog2_p->cry();cat2_p->cry();system("pause");return 0;
}

3.4 dynamic_cast

dynamic_cast强制类型转换:

  • 用于有继承关系的类指针之间转换。
  • 用于有交叉关系的类指针之间的转换。
  • 具有类型检查的功能。
  • 需要虚函数的支持。

dynamic是与继承相关的类型转换关键字,dynamic_cast要求相关的类中必须有虚函数。用于直接或间接继承关系的指针(引用之间)。

对于指针:

  • 转换成功:得到目标类型指针。
  • 转换失败:得到一个空指针。

对于引用:

  • 转换成功:得到目标类型的引用。
  • 转换失败:得到一个异常操作信息。

编译器会检查dynamic_cast的使用是否正确,类型转换的结果只能在运行阶段才能得到。

dynamic的使用:

#include <iostream>using namespace std;class Animal {public:virtual void cry() = 0;
};class Cat :public Animal
{public:void cry(){cout << "喵喵瞄" << endl;}void play(){cout << "爬爬树"<<endl;}};class Dog :public Animal
{public:void cry(){cout << "汪汪汪" << endl;}void play(){cout << "溜达溜达" << endl;}};void animalPlay(Animal& animal) {animal.cry();try {Dog& pDog = dynamic_cast<Dog&>(animal);pDog.play();}catch (std::bad_cast bc) {cout << "不是狗,那应该是猫" << endl;}try {Cat& pCat = dynamic_cast<Cat&>(animal);pCat.play();}catch (std::bad_cast bc) {cout << "不是猫,那应该是上面的狗" << endl;}}void animalPlay(Animal* animal) {animal->cry();Dog* pDog = dynamic_cast<Dog*>(animal);if (pDog) {pDog->play();}else {//pDog == NULLcout << "不是狗,别骗我!" << endl;}Cat* pCat = dynamic_cast<Cat*>(animal);if (pCat) {pCat->play();}else {//pDog == NULLcout << "不是猫,别骗我!" << endl;}
}int main(void) {Dog* dog1 = new Dog();Animal* a1 = dog1;//animalPlay(a1);Dog dog2;animalPlay(dog2);Cat* cat1 = new Cat();Animal* a2 = cat1;//animalPlay(a2);Cat cat2;animalPlay(cat2);system("pause");return 0;
}

新式类型转换以C++关键字的方式出现:

  • 编译器能够帮助检查潜在的问题;
  • 非常方便的在代码中定位;
  • 支持动态类型识别(dynamic_cast)。

3.5 类型转换使用建议

1)static_cast静态类型转换,编译的时c++编译器会做编译时的类型检查;隐式转换;基本类型转换,父子类之间合理转换。

2)若不同类型之间,进行强制类型转换,用reinterpret_cast<>() 进行重新解释。建议:C语言中能隐式类型转换的,在c++中可用 static_cast<>()进行类型转换。因C++编译器在编译检查一般都能通过;C语言中不能隐式类型转换的,在c++中可以用 reinterpret_cast<>() 进行强制类型解释。

总结:static_cast<>()和reinterpret_cast<>() 基本上把C语言中的 强制类型转换给覆盖,注意reinterpret_cast<>()很难保证移植性。

3)dynamic_cast<>(),动态类型转换,安全的虚基类和子类之间转换;运行时类型检查。
4)const_cast<>(),去除变量的只读属性。

最后的忠告:程序员必须清楚的知道: 要转的变量,类型转换前是什么类型,类型转换后是什么类型,转换后有什么后果。

C++大牛建议:一般情况下,不建议进行类型转换;避免进行类型转换。


参考资料:

  1. C语言进阶剖析教程
  2. C++深度解析教程
  3. C/C++从入门到精通-高级程序员之路【奇牛学院】

C/C++中的数据类型转换相关推荐

  1. WPF中在XAML中实现数据类型转换的两种方法

    WPF中在XAML中实现数据类型转换的两种方法 原文:WPF中在XAML中实现数据类型转换的两种方法 熟悉数据绑定的朋友都知道,当我们在Model中获取一个对象的数据,常常需要对其进行数据转换后显示在 ...

  2. java数据类型的转换函数_JAVA中常用数据类型转换函数

    JAVA中常用数据类型转换函数: string->byte Byte static byte parseByte(String s) byte->string Byte static St ...

  3. c语言强制转换字符类型,C语言中的数据类型转换问题

    C语言中的数据类型转换问题 ● 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128-127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围 ...

  4. VBA中的数据类型转换

    VBA中的数据类型转换  在VBE中打开对象浏览器,按照下图操作: 找到VBA库并输入Conversion(转换)找到该模块,里面提供了数据转换函数.  VBA提供了两套内置的数据类型转换函数,第一组 ...

  5. Java类Demo中存在_Java中的数据类型转换

    先来看一个题: Java类Demo中存在方法func0.func1.func2.func3和func4,请问该方法中,哪些是不合法的定义?( ) public class Demo{ float fu ...

  6. JS中的数据类型转换:String转换成Number的3种方法

    今天有个学员问了个关于数据类型转换的问题,我觉得这个是可以给大家说一下的. JavaScript中,可以通过以下3种方法来将string值转换成number: 1.调用Number()来对string ...

  7. Java中的数据类型转换

    Ťhis post was originally published on attacomsian.com/blog. 与PHP或JavaScript不同,Java是一种强类型的编程语言. 从本质上讲 ...

  8. C/C++中的数据类型转换()/static_cast/dynamic_cast/const_cast/reinterpret_cast

    文章目录 前言 数据类型自动转换 C语言中的强制类型转换 C++中的强制类型转换 static_cast dynamic_cast const_cast reinterpret_cast 强转关键字的 ...

  9. C语言中强制数据类型转换

    字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128-127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围是0-255(有些机器把char ...

最新文章

  1. R语言dir函数获取目录中文件或者文件夹名称实战
  2. 《Windows 系列》- 右击添加管理员权限
  3. 专栏-美国人口和都市区
  4. Kafka消息序列化和反序列化(上)
  5. 经典算法系列之(一) - BitMap [数据的压缩存储]
  6. 20121108团队博客(苏若)
  7. 年后跳槽必备的 Java 题库,全网最全!
  8. 题529. 扫雷游戏
  9. 相关性分析:Pearson、Kendall、Spearman
  10. 小话设计模式(十三)职责链模式
  11. 你们要的《Java工程师成神之路》高清版思维导图,来了!
  12. 服务器无线桥接技巧,服务器无线桥接设置方法
  13. 读书:《有无之境:王阳明哲学的精神》
  14. 不同分发平台的区别和特点
  15. Android 常用API自查表(二)
  16. 社保html源码,社保查询.html
  17. 01-空投Lynda
  18. 什么是网络流量劫持?揭秘详解黑客劫持的攻击手段与防御方法 (一)
  19. linux网络编程:splice函数和tee( )函数高效的零拷贝
  20. 关于微软AD的LDAP的一篇好文章

热门文章

  1. 7.2 PCA-机器学习笔记-斯坦福吴恩达教授
  2. STM32 电机教程 16 - PMSM电机磁场定向控制原理
  3. 响应接收窗口大小( ra-ResponseWindowSize)
  4. MASH结构相噪分析的simulink仿真
  5. 详解「递归」正确的打开方式
  6. 基于linux的ARM设备升级,烧写Nand flash总结
  7. 在Windows下使用gcc
  8. 对Java单例模式 volatile关键字作用的理解
  9. spring 整合junit进行测试
  10. YARN配置Kerberos认证