static_cast与dynamic_cast转换

2023-10-26

一 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++对象模型中,对象实例最前面的就是虚函数表指针,

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

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

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



FROM:  http://www.cnblogs.com/bastard/archive/2011/12/14/2288117.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

static_cast与dynamic_cast转换 的相关文章

  • go并发爬虫

    说明 最大20线程 搜索深度不大于3的网页 并打印出来 当搜索的不是网页的时候 存在bug 还在学习 希望有大佬告知怎么解决 package main import fmt log net http golang org x net htm
  • ReactNative系列之三十一业务bundle拆分及动态加载实例

    2018 12 17日志 1 github上的源代码更新 修复windows上生成bundle内路径的异常处理 暂时先放出思路 近期会做一期视频解析及源码下载 敬请关注 演示视频 https pan baidu com s 1FYVYgSe
  • http请求 状态码204

    今天在调试接口的时候遇到个问题 一个请求走了两次 一次204 一次200 且 请求204的 Request Method 是 OPTIONS 在网上查看资料后得知 是因为跨域而引起的 OPTIONS是一种 预检请求 浏览器在处理跨域访问的请
  • 【C++】基础语法7--继承

    继承 意义 增加代码利用率 语法 class 类名1 权限 父类2 类名1被称为 子类 或者 派生类 类名2被称为 父类 或者 基类 class dog public class Taidi public dog 继承方式 公共继承方式 p
  • 刷脸支付成功路上任何事都需要经过历练

    刷脸支付自出世以来 争议从未断过 有人认为刷脸支付十分安全便捷 是可以替代扫码支付的支付方式首选 也有人认为刷脸支付会泄露人脸信息造成安全隐患从而拒绝使用 关于刷脸支付安全性 支付宝微信早已出面解释并表示刷脸支付十分安全 也承诺若有因刷脸支
  • 一步一步学习openfire+spark(1)

    以前写过一篇关于openfire的文章 内容比较孤立 写的也比较简单 没有实际意义 正好公司使用的是这个平台 现在从新开始 对openfire这个框架进行系统性的学习 深入的了解openfire以及和openfire配套的spark的开发
  • 按步长对遥感数据进行批量裁剪

    该代码支持多图像裁剪 先将tif格式的图片转为png 再对多个png图片进行批量裁剪 批量裁剪 import os import gdal makeData import numpy as np from osgeo import gdal
  • 量化策略——准备1 系列简介

    文章目录 系列简介 系列重点 避坑 系列简介 量化策略 xxxx 是博主近期新开的一个系列 主要有以下四个方面的内容 量化选股 选择大概率赚钱的好股票 量化择时 选择低买高卖的好时机 量化套利 利用不同市场 品种 价格共识等 进行价差套利
  • 零基础可以学习Python吗?转行小白怎么学Python?

    Python学习常用的技巧有这些 一是要明确自己的学习目的 二是从易到难 循序渐进 三是合理的选择资料 有所取舍 四是坚定自己的信念 以下是关于Python学习技巧的具体介绍 1 明确自己的学习目的 每个人学Python的初衷绝对是不一样的
  • 【工具类】工具类中使用@Autowired

    Component public class Util private static String b Autowired private String a PostConstruct public void init b a Compon
  • SQL server删除表信息代码

    SQL server删除表信息代码 1 delete删除 delete from table 只是删除了表中的内容 并没有把表删除 2 drop删除 drop table 表名 把整个表都删除 3 truncate删除 truncate t
  • 通用mybatis执行sql工具系列解决方案lingdu

    整套逻辑可执行保存到数据库中的sql例如 select from a where a name ling name ling name中的name是由前端传入的参数 经过Lingdu类的动态封装 传入到mapper xml中的sql字符串中
  • python 处理hbase数据

    使用Python调用happybase库 1 thrift 是facebook开发并开源的一个二进制通讯中间件 通过thrift 我们可以用Python来操作Hbase 首先开启Hadoop平台的HadoopMaster的thrift服务

随机推荐

  • 使用webpack中的externals配置项如何配置

    externals配置项用于配置那些不需要打包进应用程序中的第三方依赖 在webpack配置文件中 可以使用以下方式配置externals module exports externals jquery jQuery 上面的配置表示jque
  • gdb C++程序coredump不显示行号问题

    编译程序的时候加上 g就可以了 编译出来的程序会大不少 然后再去gdb就能显示行号了 直接就能定位到具体那一行导致的程序coredump
  • 虚拟机下为ubuntu添加硬盘

    1 在Vm中关闭Ubuntu 设置 中 添加新的硬件设备 选择Hard Disk 点击下一步 2 选择硬盘类型 可以选择IDE 或是SCSI 这里选择SCSI 3 选择虚拟新硬盘的位置 命名 Ubuntu2 vmdk 4 设定硬盘大小 随便
  • python解带L1正则的最小二乘

    给定 H R d n H in R d times n
  • 存储卡目录变成未知文件?这些技巧能让你恢复数据!

    当存储卡的目录变成未知文件时 我们无法直接访问存储卡中的数据 但是 这并不意味着这些数据永远无法恢复 以下是几种可能恢复存储卡数据的方法 使用数据恢复软件 从互联网上下载并安装专业的数据恢复软件这些软件可以扫描存储卡 找回已删除或损坏的数据
  • 用MATLAB的GUI绘图的一个简单例子

    本文参考自https jingyan baidu com article 0f5fb099ade1626d8334ead0 html 略加改动 常用MATLAB进行一些计算 使用GUI功能的话调整参数的时候会比较方便 首先在MATLAB中选
  • FCA-FineReport帆软认证报表工程师(FCA)考试考题

    Part 1 判断题 总分 60分 得分 56 第1题 判断题 进行决策系统平台目录管理时 链接的地址可以选择使用相对路径或绝对路径 得分 2分 满分 2分 正确答案 A A 正确 B 错误 第2题 判断题 次级管理员可新建 编辑 删除有权
  • 爬虫的“黄金搭档”---requests库的详细介绍

    什么是requests Requests is an elegant an simple HTTP library for Python Requests是一个优雅而简单的HTTP库 requests库是一个常用的用于http请求的模块 它
  • 转发UGUI事件响应

    示例 点击UI时 被遮挡的UI也响应 using System Collections using System Collections Generic using System Linq using UnityEngine using U
  • SQL之DML

    DML Data Manipulation Language 数据操作语言 用来对数据库中表的数据记录进行增删改操作 insert 添加数据 update 修改数据 delete 删除数据 1 给指定字段添加数据 insert into 表
  • SlideLive:基于Elasticsearch Suggester实现搜索框提示功能

    简介 SlideLive网站使用Elasticsearch作为文档的搜索引擎 我们需要在搜索下拉框实现如下三种功能 自动补全 Auto Completion 纠错 热词推荐 ElasticSearch 为我们提供了Suggester功能 可
  • Hive整理

    文章目录 1 Hive 概述 2 1 Hive 优缺点 2 2 Hive 基础架构 2 HQL 转化为 MR 过程 3 Hive和RDBMS有什么异同 4 Hive 元数据保存方式 5 内部表 和 外部表 6 Hive 如何进行权限控制 7
  • 三年内人人有FIL,FIL 世界零撸板块引发全球流量狂潮!

    FIL 世界零撸板块自5月27日推出以来 就获得了全球Filecoin社区的热烈追捧 在短短一周内就吸引了全球20万粉丝的加盟 引发了全球价值流量狂潮 FIL世界是一个基于Filecoin整个产业链的综合性服务平台 致力于为IPFS行业生态
  • 【Vue实用功能】Vue实现文档在线预览功能,在线预览PDF、Word、Excel、ppt等office文件

    文章目录 TOC 文章目录 方法一 Luckysheet 预览 方法二 Office Web 查看器 微软的开发接口 方法三 XDOC文档预览云服务 预览pdf word xls ppt 方法一 Luckysheet 预览 Luckyshe
  • 服务器系统2022安装wsl2,微软win10子系统wsl2安装教程(附三个实例应用场景)

    wsl2与今年6月份微软buld的大会上发布消息 7月15日左右开始正式加入windows inside版本 熟悉wls win10子系统 一代的都知道 这东西把linux系统的操作直接带入到win10系统 随便启动cmd或powershe
  • 算法设计与分析-分治实验-第二题

    题目 循环赛日程表的设计 设计一个满足以下要求的比赛日程表 n 2k 1 每个选手必须与其他n 1个选手各赛一次 2 每个选手一天只能赛一次 3 循环赛一共进行n 1天 要求 输入选手的数量 需要有效性检查 满足n 2k条件 以矩阵形式输出
  • 【PCIe】Linux下PCIe驱动开发与学习

    目录 1 PCIe概述 2 pcie总线的拓扑结构 3 PCIe配置空间 3 1 PCI标准配置空间头 0 64 bytes 3 2 PCI capbility结构 64
  • 成功是一种境界

    第1节 完成三十岁前的积累 准备做一个成功的男人 1 Chapter Six 完成三十岁前的积累 准备做一个成功的男人 二十几岁是褪尽青涩 走向成熟的男人 二十几岁是很有紧迫感的年龄 如果男人到了三十还一事无成 人们就不再像对二十几岁时那样
  • 2.5 Java方法调用——类名调用方法、对象调用方法

    文章目录 方法 1 什么是方法 2 方法如何定义 方法怎么使用 通过类名调用方法 static 修饰方法 类名调用 通过对象调用方法 不加static修饰 new一个对象 对象调用 方法 1 什么是方法 类似于C语言中的函数 解决某一个问题
  • static_cast与dynamic_cast转换

    一 C语言中存在着两种类型转换 隐式转换和显式转换 隐式转换 不同数据类型之间赋值和运算 函数调用传递参数 编译器完成 char ch int i ch 显示转换 在类型前增加 Type 变量 对变量进行的转换 用户显式增加 char pc