static_cast与dynamic_cast转换

static_cast与dynamic_cast转换  

       

一 C语言中存在着两种类型转换:

隐式转换和显式转换

隐式转换:不同数据类型之间赋值和运算,函数调用传递参数……编译器完成

char ch;
int i = ch;

显示转换:在类型前增加 :(Type)变量 对变量进行的转换。用户显式增加

char *pc = (char*)pb;
void *ps = (void*)pa;


二 C++
中的类型转换

  通过这两种方式,C语言中大部分的类型转换都可以顺利进行。

至于能不能进行转换,转换后的结果如何,编译器不管需要用户自己去控制。

  C++继承了C中的隐式和显式转换的方式。但这种转换并不是安全和严格的,

加上C++本身对象模型的复杂性,C++增加了四个显示转换的关键字。(C++是强类型语言)

static_castdynamic_castconst_staticreinterpret_cast

 

1 static_cast

(1)用于基本的数据类型转换(char,int),及指针之间的转换

复制代码
test_enum type = test_enum_1;

char a ;
int b = static_cast<int>(a);
char c = static_cast<char>(b);
type = static_cast<test_enum>(b);

char* pa = NULL;
int *pb = (int*)pa;
//int *pb = static_cast<int*>(pa); //error
//pa = static_cast<char*>(pb) //error
char *pc = (char*)pb;
//char *pc = static_cast<char*>(pb); //error

void *p = static_cast<void*>(pa);
pb = static_cast<int*>(p);
pc = static_cast<char*>(p);
复制代码

 

(2)类层次中基类与子类成员函数指针的转换

 

复制代码
class A
{

public:
void set(){}
};

class B:public A
{
public:
void set(){}
};

typedef void (A::*PS_MFunc)();   //指向类A的成员函数指针

PS_MFunc func = &A::set;
func = static_cast<PS_MFunc>(&B::set); //基类指向子类成员函数指针,必须进行转换
复制代码


(3)类层次结构中基类与子类指针或引用之间的转换  

   上行转换:子类指针或引用转换成基类表示——安全

  下行转换:基类指针或引用转换成子类表示——危险(没有动态类型检查)

复制代码
class A
{
};
class B:public A
{
};
class C:public A
{
};
class D
{
};

A objA;
B objB;
A* pObjA = new A();
B* pObjB = new B();
C* pObjC = new C();
D* pObjD = new D();

objA = static_cast<A&>(objB); //转换为基类引用
objA = static_cast<A>(objB);
objB = static_cast<B>(objA); //error 不能进行转换

pObjA = pObjB; //right 基类指针指向子类对象
//objB = objA; //error 子类指针指向基类对象
pObjA = static_cast<A*>(pObjB); //right 基类指针指向子类
pObjB = static_cast<B*>(pObjA); //强制转换 OK 基类到子类
//pObjC = static_cast<C*>(pObjB); //error 继承于统一类的派生指针之间转换
//pObjD = static_cast<D*>(pObjC); //error 两个无关联之间转换
复制代码

 

2 dynamic_cast

(1)继承关系的类指针对象或引用之间转换

        

复制代码
class A
{
};
class B:public A
{
};
class C:public A
{
};
class D
{
};

A objA;
B objB;
A* pObjA = new A();
B* pObjB = new B();
C* pObjC = new C();
D* pObjD = new D();
//objA = dynamic_cast<A>(objB); //error 非引用

objA = dynamic_cast<A&>(objB);
//objB = dynamic_cast<B&>(objA); //error A 不是多态类型不能转换 若有虚函数则可以进行转换

pObjA = dynamic_cast<A*>(pObjB);
//pObjB = dynamic_cast<B*>(pObjA); //error A 继承关系 不是多态类型不能转换
//pObjB = dynamic_cast<B*>(pObjC); //error C 兄弟关系 不是多态类型不能转换
//pObjB = dynamic_cast<B*>(pObjD); //error D 没有关系 不是多态类型不能转换
复制代码

 

 

(2)包含有虚函数之间对象指针的转换   

复制代码
class A
{
Public:
Virtual ~A(){}
};
class B:public A
{
};
class C:public A
{
};
class D
{
Public:
Virtual ~D(){}
};
pObjB = dynamic_cast<B*>(pObjA);    // worning 继承关系 父类具有虚函数 多态
pObjB = dynamic_cast<B*>(pObjD); //worning 没有关系 D是多态类型可以转换
//以上结果:pObjB == NULL 此处会发生一个运行时错误
复制代码

         也就是说除了基类指针指向子类对象,可以没有虚函数外,其它要进行dynamic_cast转换必须具有虚函数才行。

那这是为什么呢?下面继续>

 

(3)dynam_cast转换的安全性

         dynamic_cast是动态转换,只有在基类指针转换为子类指针时才有意义。

(子类指针转换为基类指针本来就是可以的:基类指针指向子类对象OK)。

但是基类指针转换为子类指针,并不是每一次都有效:只有基类指针本身指向的是一个派生类的对象,

然后将此基类指针转换为对应的派生类指针才是有效的。这种情况在表面上是无法判定的。此时dynamic就发挥了作用。

情况1: static_cast转换       

复制代码
class A
{
};
class B:public A
{
public:
int m; //B 成员
};

A* pObjA = new A();
B* pObjB = NULL;
pObjB = static_cast<B*>(pObjA); //基类指针转化为子类指针 成功转换
pObjB->m = 10;   //实际中pObj所指向的对象 是A类对象
//上面会发生什么呢,在VC6.0中正常运行。。。?

//如果:

pObjB = dynamic_cast<B*>(pObjA); //error 基类A没有虚函数 不构成多态
复制代码

情况2:     dynamic_cast转换    

复制代码
class A
{
public:
virtual ~A(){} //虚函数 多态
};
class B:public A
{
public:
int m;
};

A* pObjA = new A();
B* pObjB = NULL;
pObjB = dynamic_cast<B*>(pObjA); //编译通过
//实际运行结果:pObjB == NULL // dynamic_cast保证转换无效 返回NULL
复制代码

         dynamic_cast转换不成功,则返回0

4 虚函数对于dynamic_cast转换的作用

  为何使用dynamic_cast转换类指针时,需要虚函数呢。

Dynamic_cast转换是在运行时进行转换,运行时转换就需要知道类对象的信息(继承关系等)。

如何在运行时获取到这个信息——虚函数表。

  C++对象模型中,对象实例最前面的就是虚函数表指针,

通过这个指针可以获取到该类对象的所有虚函数,包括父类的。

因为派生类会继承基类的虚函数表,所以通过这个虚函数表,我们就可以知道该类对象的父类,在转换的时候就可以用来判断对象有无继承关系。

  所以虚函数对于正确的基类指针转换为子类指针是非常重要的。

 

转载于:https://www.cnblogs.com/yuanming/p/7063672.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue使用iview Timeline 时间轴不显示问题

vue Timeline 时间轴不显示渲染的效果 官网代码 <Timeline pending><TimelineItem>发布1.0版本</TimelineItem><TimelineItem>发布2.0版本</TimelineItem><TimelineItem>发布3.0版本</TimelineItem><TimelineItem><a href…

Java EE 6 Web配置文件。 在云上。 简单。

Java SE还可以。 Java EE是邪恶的。 这就是我一直想的。 好吧&#xff0c;现在不再了。 让我分享我的经验。 几周前&#xff0c;我开始考虑将旧版spring hibernate tomcat应用程序移植到新平台上&#xff1a; SAP NetWeaver云 。 我知道您在极客那里的想法&#xff1a;…

Kubernetes核心概念总结

1、基础架构 1.1 Master Master节点上面主要由四个模块组成&#xff1a;APIServer、scheduler、controller manager、etcd。 APIServer。APIServer负责对外提供RESTful的Kubernetes API服务&#xff0c;它是系统管理指令的统一入口&#xff0c;任何对资源进行增删改查的操作都要…

php连接mysql数据,php连接mysql数据库

$sql_link mysql_connect("主机名","登入用户名","登入用户名密码");如果连接成功&#xff0c;就会返回一个mysql句柄,可以简单的理解成这个$sql_link 是php跟mysql的一个桥梁&#xff0c;通过该桥梁我们可以进入到mysql。进入到mysql之后&…

url存在宽字节跨站漏洞_利用WebSocket跨站劫持(CSWH)漏洞接管帐户

在一次漏洞悬赏活动中&#xff0c;我发现了一个使用WebSocket连接的应用&#xff0c;所以我检查了WebSocket URL&#xff0c;发现它很容易受到CSWH的攻击(WebSocket跨站劫持)有关CSWH的更多详细信息&#xff0c;可以访问以下链接了解https://www.christian-schneider.net/Cross…

php 数组对比 unset,如何区分PHP中unset,array_splice的区别

1.使用的函数a.函数unset()unset ( mixed $var , mixed $... ? ) : voidunset()销毁指定的变量。b.函数array_slice()array_splice(array,start,length,array)array表示数组。start表示删除元素的开始位置。length表示被移除的元素个数&#xff0c;也是被返回数组的长度。(可…

前端基础-CSS的各种选择器的特点以及CSS的三大特性

一、 基本选择器二、 后代选择器、子元素选择器三、 兄弟选择器四、 交集选择器与并集选择器五、 序列选择器六、 属性选择器七、 伪类选择器八、 伪元素选择器九、 CSS三大特性 一、 基本选择器 1、id选择器 #1、作用&#xff1a;根据指定的id名称&#xff0c;在当前界面中找…

使用JavaCV进行手和手指检测

这篇文章是Andrew Davison博士发布的有关自然用户界面&#xff08;NUI&#xff09;系列的一部分&#xff0c;内容涉及使用JavaCV从网络摄像头视频提要中检测手。 注意&#xff1a;可以从http://fivedots.coe.psu.ac.th/~ad/jg/nui055/下载本章的所有源代码。 第5章的彩色斑点检…

不能装载文档控件。请在检查浏览器的选项中检查浏览器的安全设置_【2020年网络安全宣传周】如何正确设置浏览器...

李夏是一个公司的职员&#xff0c;一天晚上加班赶制文档&#xff0c;由于要向客户汇报产品情况&#xff0c;需要获取大量网上信息&#xff0c;然而在制作中却发现浏览器的网页打不开了。第二天原计划向客户展示的材料未能完整汇总&#xff0c;客户见面对接效果也打了折扣。在当…

用装饰器设计模式装饰

装饰图案是广泛使用的结构图案之一。 此模式在运行时动态更改对象的功能&#xff0c;而不会影响对象的现有功能。 简而言之&#xff0c;此模式通过包装将附加功能添加到对象。 问题陈述&#xff1a; 想像一下我们有一个比萨饼&#xff0c;该比萨饼已经用番茄和奶酪烤制的情况。…

vcpkg安装_微软牌包管理器vcpkg更新及路线图计划

蝎子vcpkg是一套跨平台&#xff0c;开源的C/C库管理器&#xff0c;今天的这篇文章是有关vcpkg主题的2020年4月博文更新。在这篇文章中&#xff0c;我们将分享有关vcpkg 2020.04发布版本的一些信息以及vcpkg的路线图(roadmap)&#xff0c;我们会在这里持续地发布有关vcpkg的最新…

CSS 盒模型与box-sizing

一、盒模型 一个web页面由许多html元素组成&#xff0c;而每一个html元素都可以表示为一个矩形的盒子&#xff0c;CSS盒模型正是描述这些矩形盒子的存在。 MDN的描述&#xff1a; When laying out a document, the browsers rendering engine represents each element as a r…

Java课程设计 购物车系统(个人博客) 201521123052 蓝锦明

1. 团队课程设计博客链接 课程设计团队博客 2. 个人负责模块或任务说明 &#xff08;1&#xff09;制作图形菜单引导界面 &#xff08;2&#xff09;定义各获取和输出类函数 3. 自己的代码提交记录截图 4. 自己负责模块或任务详细说明 import java.text.NumberFormat; public c…

7-12(图) 社交网络图中结点的“重要性”计算(30 分)

在社交网络中&#xff0c;个人或单位&#xff08;结点&#xff09;之间通过某些关系&#xff08;边&#xff09;联系起来。他们受到这些关系的影响&#xff0c;这种影响可以理解为网络中相互连接的结点之间蔓延的一种相互作用&#xff0c;可以增强也可以减弱。而结点根据其所处…

linux系统的安装程序,Linux系统安装

为了不影响本机系统&#xff0c;建议在虚拟机上创建并安装Linux系统&#xff0c;本次安装centos7 64位的镜像。详细步骤如下&#xff1a;1、首先在虚拟机主页创建新的虚拟机。... 图1.1 2、选择自定义安装&#xff0c;这样方便我们更好了解虚拟机&#xff0c;然后点击下一步。.…

百米路由器2登陆地址_腾达无线路由器怎么安装,真的不错

腾达无线路由器怎么安装1、WAN口连接宽带进线(即网络公司进来的线或猫出来的线&#xff0c;一般颜色不一样)、LAN口连接局域网内的电脑。2、设置所连接电脑的IP地址。右键点击网上邻居属性3、右键点击本地连接属性4、选择Internet协议TCP/IP属性5、点击选择自动获得IP地址和自动…

JavaFX 2 XYCharts和Java 7功能

我最喜欢的JavaFX 2功能之一是它在javafx.scene.chart包中提供的标准图表。 该软件包提供了几种不同类型的现成图表。 除了其中之一&#xff08; PieChart &#xff09;以外&#xff0c;所有其他都是“ 2轴图”&#xff08; XYChart的特定实现&#xff09;。 在本文中&#xff…

前端基础-HTML的的标签详解

阅读目录 一、head内常用标签二、 HTML语义化三、 字符实体四、 h系列标签五、 p标签六、 img标签七、 a标签八、 列表标签九、 table标签十、 form标签 一、 head内常用标签 1、meta相关 #1、指定字符集<meta charset"gbk">#2、页面描述<meta name"…

new失败跟踪函数_WinDbg预览时间线:调试器中的时间线可以允许用户记录跟踪

时间旅行调试(TTD)允许用户记录跟踪&#xff0c;这些跟踪是对程序执行的记录。时间线是执行过程中发生的事件的直观表示&#xff0c;这些事件可以是包括断点&#xff0c;内存读/写&#xff0c;函数调用和返回以及异常。使用时间线窗口可以快速查看重要事件&#xff0c;了解相对…

linux 进程的执行时间,Linux 获取进程执行时间

Linux 获取进程执行时间1 前言测试一个程序的执行时间, 时间包括用户 CPU 时间系统 CPU 时间时钟时间之前获取之前时间都是在程序的 main 函数用 time 函数实现, 这个只能粗略的计算程序的执行时间, 不能准确的获取其他时间在看 APUE 时, 书中有关程序时间测试程序, 非常正规, …