• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > C++中的四种类型转换

C++中的四种类型转换

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c++强制类型转换,c++类型转换,c++强制转换数据类型,c++数据类型转换,c++类型转换函数等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

1 引子

这篇笔记是根据StackOverflow上面的一个问题整理而成,主要内容是对C/C++当中四种类型转换操作进行举例说明。在之前其实对它们都是有所了解的,而随着自己在进行总结,并敲了一些测试示例代码进行验证之后,对它们的理解又深刻了一些。

总所周知,在C++ 当中引入了四种新的类型转换操作符:static_cast, dynamic_cast, reinterpret_cast,还有const_cast。就自己见过的一些C++代码当中,它们的使用其实并不普遍。不少程序员依然乐于去使用C-like的类型转换,因为它强大且编写起来又简单。据说C-Like类型转换操作符的作用实际上已经包括了static_cast, const_cast和reinterpret_cast三种操作符,你相信吗?一起来着看。

注:上面提到的C-Like类型转换操作有如下的两种形式,这一点大家一定都不会陌生。

(new-type) expression
new-type (expression)
</div>

2 static_cast vs dynamic_cast

之所以把static_cast与dynamic_cast两兄弟放在一起是因为它们两者对比起来更容易记得住。首先,从名称上面它们就有语义相对的关系,一“静”一“动”。另外,在功能上面也在一定程度上体现了这一对比的特性,如dynamic_cast的Run-time Checkingt,static_cast在编译时增加的类型检测。简单而言:

static_cast: 1)完成基础数据类型,2)同一个继承体系中类型的转换
dynamic_cast:使用多态的场景,增加了一层对真实调用对象类型的检查

2.1 从C-Like到static_cast

static_cast对于基础类型如int, float, char以及基础类型对应指针的处理大多情况下恰如C-Like的转换一样,不过static_cast会来得更加安全。

char c = 10;      // 1 个字节
int *p = (int *)&c;  // 4 个字节(32bit platform)

*p = 5;        // 内存踩脏
int *q = static_cast<int *>(&c); // 使用static_cast可在编译阶段将该错误检查出来。
</div>


对于自定义类型的处理,相比C-Like而言,它也多了一层保护,也就是它不支持在不属于同一继承体系的类型之间进行转换。但是C-Like就可以办到,看下面这个例子:

#include <iostream>

class A
{
public:
 A(){}
 ~A(){}
 
private:
 int i, j;
};

class C
{
public:
 C(){}
 ~C(){}

 void printC()
 {
  std::cout <<"call printC() in class C" <<std::endl;
 }
private:
 char c1, c2;
};

int main()
{ 
 A *ptrA = new A;
 //C *ptrC = static_cast<C *>(ptrA);
 // 编译无法通过,提示:
 // In function ‘int main()':
 // error: invalid static_cast from type ‘A*' to type ‘C*'
 
 C *ptrC = (C *)(ptrA);
 ptrC->printC();
 // 编译正常通过。
 // 尽管这个时候能够正常调用printC,但实际上这种做法的结果是“undefined”
 // 尝试过,如果添加一些数据成员的运算,这个时候将会使得运算结果无法预测
 // 所以,在运行时候该逻辑相关的行为是不清晰的。
 
 return 0;
} 

</div>

2.2 static_cast对于自定义类型的转换

上面这个小例子简单对比了static_cast与C-Like在针对不同继承体系的类之间表现的差异性,现在先把范围缩小到同一继承体系当中的类型转换。(注:这里所说的类型一般是针对类的指针或者类的引用)

static_cast针对同一继承体系的类之间的转换,它既可以进行upcast也可以进行downcast。一般来说,在进行upcast时是没有问题的,毕竟子类当中一定包含有父类的相关操作集合,所以通过转换之后的指针或者引用来操作对应的对象,其行为上是可以保证没问题。这和使用static_cast与使用C-Like或者直接隐式转换效果一样(当然,其结果是否符合程序员本身的预期与当时的设计有关系)。

需要注意的是,使用static_cast进行downcast应该避免,因为它可以顺利逃过编译器的法眼,但在运行时却会爆发未定义的问题:

#include <iostream>

class A
{
public:
 A():i(1), j(1){}
 ~A(){}
 
 void printA()
 {
  std::cout <<"call printA() in class A" <<std::endl;
 }
 
 void printSum()
 {
  std::cout <<"sum = " <<i+j <<std::endl;
 }
 
private:
 int i, j;
};

class B : public A
{
public:
 B():a(2), b(2) {}
 ~B(){}

 void printB()
 {
  std::cout <<"call printB() in class B" <<std::endl;
 }
 
 void printSum()
 {
  std::cout <<"sum = " <<a+b <<std::endl;
 }
 
 void Add()
 {
  a++;
  b++;
 }
 
private:
 double a, b;
};

int main()
{   
 B *ptrB = new B;
 ptrB->printSum();
 //打印结果:sum = 4
 A *ptrA = static_cast<B *>(ptrB);  
 ptrA->printA();
 ptrA->printSum();
 //打印结果:sum = 2
 //在进行upcast的时候,指针指向的对象的行为与指针的类型相关。
 
 
 ptrA = new A;
 ptrA->printSum();
 //打印结果:sum = 2 
 ptrB = static_cast<B *>(ptrA);
 ptrB->printB();
 ptrB->printSum(); 
 //打印结果:sum = 0
 //在进行downcast的时候,其行为是“undefined”。
 
 //B b;
 //B &rB = b;
 //rB.printSum();
 //打印结果:sum = 4
 //A &rA = static_cast<A &>(rB);  
 //rA.printA();
 //rA.printSum();
 //打印结果:sum = 2
 //在进行upcast的时候,引用指向的对象的行为与引用的类型相关。
 
 //A a;
 //A &rA = a;
 //rA.printSum();
 //打印结果:sum = 4
 //B &rB = static_cast<B &>(rA);  
 //rB.printB();
 //rB.printSum();
 //打印结果:sum = 5.18629e-317 
 //在进行downcast的时候,其行为是“undefined”。
 
 return 0;
}

</div>

如上,static_cast在对同一继承体系的类之间进行downcast时的表现,与C-Like针对分属不同继承体系的类之间进行转换时的表现一样,将是未定义的。所以,应该尽可能使用static_cast执行downcast转换,更准确的说,应该尽可能避免对集成体系的类对应的指针或者引用进行downcast转换。

既然这样,那是不是在软件开发过程当中就不会存在downcast的这种情况了呢?实际上不是的。一般来说,进行downcast的时候一般是在虚继承的场景当中,这个时候dynamic_cast就上场了。

2.3 dynamic_cast

dynamic_cast的使用主要在downcast的场景,它的使用需要满足两个条件:

downcast时转换的类之间存在着“虚继承”的关系
转换之后的类型与其指向的实际类型要相符合
dynamic_cast对于upcast与static_cast的效果是一样的,然而因为dynamic_cast依赖于RTTI,所以在性能上面相比static_cast略低。

#include <iostream>
#include <exception>

class A
{
public:
 virtual void print() 
 {
  std::cout <<"Welcome to WorldA!" <<std::endl;
 }
};

class B : public A
{
public:
 B():a(0), b(0) {}
 ~B(){}
 virtual void print() 
 {
  std::cout <<"Welcome to WorldB!" <<std::endl;
 }
private:
 double a, b;
};

int main()
{
 B *ptrB = new B;
 A *ptrA = dynamic_cast<A *>(ptrB);
 ptrA->print();
 //在虚继承当中,针对指针执行upcast时dynamic_cast转换的效果与static_cast一样
 //对是否存在virtual没有要求,会实际调用所指向对象的成员。
  
 //A *ptrA = new A;
 //B *ptrB = dynamic_cast<B *>(ptrA);
 //ptrB->print();
 //Segmentation fault,针对指针执行downcast时转换不成功,返回NULL。
 
 //A a;
 //A &ra = a;
 //B &b = dynamic_cast<B &>(ra);
 //b.print();  
 //抛出St8bad_cast异常,针对引用执行downcast时转换不成功,抛出异常。
 
 //ptrA = new A;
 //ptrB = static_cast<B *>(ptrA);
 //ptrB->print();
 //使用static_cast进行downcast的时候,与dynamic_cast返回NULL不同,
 //这里会调用ptrB实际指向的对象的虚函数。
  
 //ptrA = new A;
 //ptrB = dynamic_cast<B *>(ptrA);
 //ptrB->print();
 //在进行downcast时,如果没有virtual成员,那么在编译时会提示: 
 // In function ‘int main()':
 // cannot dynamic_cast ‘ptrA' (of type ‘class A*') to type ‘class B*' (source type is not polymorphic)
 
 return 0;
}

</div>

从这个例子可以看出,在虚继承场景下,能够使用dynamic_cast的地方一定可以使用static_cast,然而dynamic_cast却有着更严格的要求,以便帮助程序员编写出更加严谨的代码。只不过,它在性能上面多了一部分开销。

3 reinterpret_cast

reinterpret_cast是最危险的一种cast,之所以说它最危险,是因为它的表现和C-Like一般强大,稍微不注意就会出现错误。它一般在一些low-level的转换或者位操作当中运用。

#include <iostream>

class A
{
public:
 A(){}
 



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C++中4种强制类型转换的区别总结
  • 简单总结C++中的修饰符类型
  • 深入讲解C++数据类型转换的相关函数的知识
  • C++中的四种类型转换
  • C++类型转换归纳总结
  • c++中的4种类型转化方式详细解析
  • 深入解析C++中的引用类型
  • 解析C++中四种强制类型转换的区别详解
  • 深入C++四种强制类型转换的总结
  • 基于c++强制类型转换的(总结)详解

相关文章

  • 2017-05-28总结C语言中const关键字的使用
  • 2017-05-28c++中new的三种用法详细解析
  • 2017-05-28C++实现显示MP3文件信息的方法
  • 2017-05-28C++计数排序详解
  • 2017-05-28C++ STL list 遍历删除出错解决方案
  • 2017-05-28关于C语言除0引发的思考
  • 2017-05-28MFC设置对话框焦点的方法简述
  • 2017-05-28简单掌握C++编程中的while与do-while循环语句使用
  • 2017-05-28在C++中自定义宏的简单方法
  • 2017-05-28怎么通过C语言自动生成MAC地址

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C++设计模式之状态模式
    • 解析C语言中如何正确使用const
    • 基于C中含有if的宏定义详解
    • 浅谈C语言共用体和与结构体的区别
    • C++中一维数组与指针的关系详细总结
    • C++中虚函数与纯虚函数的用法
    • C++ 类的静态成员深入解析
    • Windows窗口消息实例详解
    • C++实现随机生成迷宫地牢
    • 老生常谈C语言动态函数库的制作和使用(推荐)

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有