C++ 类型转换

2023-11-17

c语言中的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换

隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败.

显式类型转化:需要用户自己处理.

int main()
{
	//隐式类型转换
	double d = 1.1;
	int i = d;
	cout << d<< endl;   //1.1
	cout << i << endl;  //1

	//显式类型转换
	int* p = &i;
	int address = (int)p;
	cout << p << endl;
	cout << address << endl;
	return 0;
}


为什么C++需要四种类型转换.

常规中c语言隐式类型转留下了一些出乎意料的坑.

例如:在字符串的插入函数中,pos为0.

  • 若end为无符号类型整数,那么end经过循环减为’负数’之后反而变成了一个很大的正数,这样很容易造成越界.
  • 若end为有符号整数,通过end >= pos 这一过程由有符号整数转换为无符号整数,这样又会造成越界.
void Insert(size_t pos, char ch)
{
	size_t size = 5;

	size_t end = size - 1;

	while (end >= pos)
	{
		//_tr[end + 1] = _str[end];
		--end;
	}
}

C风格的转换格式很简单,但是有不少缺点的:

  • 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  • 显式类型转换将所有情况混合在一起,代码不够清晰.

C++强制类型转换

static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);
	cout << a << endl;
	return 0;
}

reinterpret_cast

reinterpret_cast一般用于两个不相关的类型转换.

int main()
{
	int a = 10;
	int* p = &a;
	int address = reinterpret_cast<int>(p);
	cout << address << endl;
	return 0;
}

const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值.

int main()
{
	const int a = 2;
	int* p = const_cast<int*>(&a);
	*p = 3;
	cout << a << endl;  //2
	cout << *p << endl; //3
	return 0;
}

注意:
1.以上代码使用const_cast实际上是删除了变量a地址的const属性,代表着我们可以利用地址p来改变变a.

2.理论上而言,a和p的值修改后打印出来是一样的.但是,由于编译器会将const修饰的变量a加载到寄存器中,打印的时候编译器便会直接从寄存器读.所以,读取a时便还是以前的值,而p中说是从内存中获取的,具有时效性,此时便为3了.

3.为了解决这一问题,我们可以使用在长变量前加上volatile关键字,表明让编译器不要从寄存器中取长变量,而应该从内存中获取.

4.static_cast类似于c语言的隐式类型转换,reinterpret_cast,const_cast类似于c语言的强制类型转换.

dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用,转换为子类对象的指针或引用(动态转换).

  • 向上转型: 子类对象指针/引用 -> 父类指针/引用.(不需要转换,赋值兼容).
  • 向下转型: 父类对象指针/引用 -> 子类指针/引(相比于c语言,使用dynamic_cast更为安全).

为什么C++要支持向下转型?

因为在Func函数中,形参为父类指针接收,可是,我们并不知道实参传的是指向父类的指针,还是指向子类的指针.

  • 如果传的是指向子类的指针,但是此时会发生向上转型,pa是父类指针,无法访问到子类成员,所以我们可以将pa强转为子类指针,这样子类指针pb既可以访问到父类成员又可以访问到子类成员了.
  • 如果传的是指向父类的指针,那么那么此时强转为子类指针pb后,访问到子类成员时,就代表访问到不属于pb所管辖的内存打空间,进而发生越界访问.
class A
{
public:
	virtual void f() {};
	int _a = 1;
};

class B : public A
{
public:
	int _b = 3;
};

void Func( A* pa )
{
	B* pb = dynamic_cast <B*>(pa);
	
	pa->_a++;

	pb->_b++;
}

int main()
{
	A aa;

	B bb;
	
	Func(&aa);
	
	Func(&bb);
}

为了访问更加安全,C++便提出了向下转型:

  • 如果pa指向子类,那么便可以强制转换,将父类指针转换为子类指针,并返回正确的地址.
  • 如果pa指向父类,那么便不可以强制类型转换,转换表达式返回为nullptr.

所以,在C++中,面对上述问题,我们可以采用dynamic_cast来强制类型转换,再通过返回值来进行判断访问范围,防止发生越界访问.

  • 如果pa指向子类,便可以通过pb访问子类所有成员.
  • 如果pa指向父类,只能pb为空,无法强制转换,pa只能访问父类成员.
class A
{
public:
	virtual void f() {};
	int _a = 1;
};

class B : public A
{
public:
	int _b = 3;
};

void Func( A* pa )
{
	B* pb = dynamic_cast<B*>(pa);

	if (pb) //pb指向子类.
	{
		cout << "转换成功" << endl;
		
		pb->_b++;
		
		pb->_a++;
		
		cout << pb->_a << ":" << pb->_a << endl;
	}
    
	else  //pb指向父类.
	{
		cout << "转换失败" << endl;

		pa->_a++;

		cout << pa->_a << endl;
	}
}

int main()
{
	A aa;

	B bb;
	
	Func(&aa);   
	
	Func(&bb);
}

延申问题

对于菱形继承来说,切片会产生偏移量,原本父类指针ptr1,ptr2应该都指子类bb,但是经过切片后,ptr1指向子类中的A1,ptr2指向子类中的A2.

在这里插入图片描述
无论采用c语言的强制转换,还是C++中的dynamic_cast强制转换.

  • 如果将子类指针转换为父类指针,该指针指向子类.那么会发生指针偏移,ptr1指* 向基类A1,解引用访问基类A1,ptr2指向基类A2,解引用访问基类A2.
  • 如果将父类指针转换为子类指针,该指针指向子类,ptr1和ptr2依旧指向子类.
class A1
{
public:
	virtual void f() {};
	int _a1 = 1;
};

class A2
{
public:
	virtual void f() {};
	int _a2= 1;
};
class B : public A1,public A2
{
public:
	int _b = 3;
};


int main()
{
	B bb;
	
	A1* ptr1 = &bb;

	A2* ptr2 = &bb;

	cout << ptr1 << endl;

	cout << ptr2 << endl;

	B* pb1 = (B*)ptr1;

	B* pb2 = (B*)ptr2;

	cout << pb1 << endl;

	cout << pb2 << endl;

    cout << "-----------------------------" << endl;

	B* pb3 = dynamic_cast<B*>(ptr1);

	B* pb4 = dynamic_cast<B*>(ptr1);

	cout << pb3 << endl;

	cout << pb4 << endl;
	
	return 0;
}

在这里插入图片描述

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

C++ 类型转换 的相关文章

  • 从实体获取单列

    如何从查询中获取单个列而不是整个对象 我可以这样做来获取整个对象 但我想要的只是名称 IList
  • 当其源是 https uri 时如何使 wpf MediaElement 播放

    在 wpf 独立应用程序 exe 中 我在主窗口中包含了 MediaElement
  • 如何查明 .exe 是否正在 C++ 中运行?

    给定进程名称 例如 程序 exe C 标准库没有这样的支持 您需要一个操作系统 API 来执行此操作 如果这是 Windows 那么您将使用 CreateToolhelp32Snapshot 然后使用 Process32First 和 Pr
  • 为什么 C# 中同一类型的隐式和显式运算符不能共存? [复制]

    这个问题在这里已经有答案了 为什么同一类中两个相同类型的运算符 显式和隐式 不能共存 假设我有以下内容 public class Fahrenheit public float Degrees get set public Fahrenhe
  • 如何调试在发布版本中优化的变量

    我用的是VS2010 我的调试版本工作正常 但我的发布版本不断崩溃 因此 在发布版本模式下 我右键单击该项目 选择 调试 然后选择 启动新实例 此时我看到我声明的一个数组 int ma 4 1 2 8 4 永远不会被初始化 关于可能发生的事
  • 从点云检测平面集

    我有一组点云 我想测试3D房间中是否有角落 所以我想讨论一下我的方法 以及在速度方面是否有更好的方法 因为我想在手机上测试它 我将尝试使用霍夫变换来检测线 然后我将尝试查看是否有三条线相交 并且它们也形成了两个相交的平面 如果点云数据来自深
  • 如果在代码中添加元素,“FindName”将不起作用

    在 WPF 应用程序中 如果在 XAML 中声明 ContentControl
  • 将 2 个字节转换为整数

    我收到一个 2 个字节的端口号 最低有效字节在前 我想将其转换为整数 以便我可以使用它 我做了这个 char buf 2 Where the received bytes are char port 2 port 0 buf 1 port
  • MSChart 控件中的自定义 X/Y 网格线

    我有一个带有简单 2D 折线图的 C Windows 窗体 我想向其中添加自定义 X 或 Y 轴标记 并绘制自定义网格线 例如 以突出显示的颜色 虚线 我查看了 customLabels 属性 但这似乎覆盖了我仍然想显示的默认网格 这是为了
  • C 与 C++ 中的 JNI 调用不同?

    所以我有以下使用 Java 本机接口的 C 代码 但是我想将其转换为 C 但不知道如何转换 include
  • 如何对STL向量进行排序?

    我想排序一个vector vector
  • 选择 asp.net CheckBoxList 中的所有项目

    ASP NET 和 C 我想要一个带有 全选 项目的复选框列表 当这个特定项目是 已选择 所有其他都将被选择 也 当选择被删除时 这个项目 也将来自所有人 其他物品 选中 取消选中 任何其他项目只会有一个 对特定项目的影响 无论选择状态如何
  • WPF DataGrid - 在每行末尾添加按钮

    我想在数据网格的每一行的末尾添加一个按钮 我找到了以下 xaml 但它将按钮添加到开头 有人知道如何在所有数据绑定列之后添加它吗 这会将按钮添加到开头而不是末尾
  • 使用 Unity 在 C# 中发送 http 请求

    如何使用 Unity 在 C 中发送 HTTP GET 和 POST 请求 我想要的是 在post请求中发送json数据 我使用Unity序列化器 所以不需要 新的 我只想在发布数据中传递一个字符串并且能够 将 ContentType 设置
  • 不使用放置 new 返回的指针时的 C++ 严格别名

    这可能会导致未定义的行为吗 uint8 t storage 4 We assume storage is properly aligned here int32 t intPtr new void storage int32 t 4 I k
  • 在二进制数据文件的标头中放入什么

    我有一个模拟 可以读取我们创建的大型二进制数据文件 10 到 100 GB 出于速度原因 我们使用二进制 这些文件依赖于系统 是从我们运行的每个系统上的文本文件转换而来的 所以我不关心可移植性 当前的文件是 POD 结构的许多实例 使用 f
  • 值和类型的简洁双向静态 1:1 映射

    我将从我想象如何使用我想要创建的代码开始 它不必完全像这样 但它是我在标题中所说的 简洁 的一个很好的例子 就我而言 它是将类型映射到相关的枚举值 struct bar foo
  • 在 C 中使用 #define 没有任何价值

    If a define没有任何价值地使用 例如 define COMMAND SPI 默认值是0吗 不 它的评估结果为零 从字面上看 该符号被替换为空 然而 一旦你有了 define FOO 预处理器条件 ifdef FOO现在将是真的 另
  • MSVC编译器下使用最大成员初始化联合

    我正在尝试初始化一个LARGE INTEGER在 C 库中为 0 确切地说是 C 03 以前 初始化是 static LARGE INTEGER freq 0 在 MinGW 下它产生了一个警告 缺少成员 LARGE INTEGER Hig
  • 如何在c中断言两个类型相等?

    在 C 中如何断言两种类型相等 在 C 中 我会使用 std is same 但搜索 StackOverflow 和其他地方似乎只能给出 C 和 C 的结果 在C中没有办法做到这一点吗 请注意 这不是询问变量是否具有某种类型 而是询问两个类

随机推荐

  • mkdir()和mkdirs()区别

    mkdir 和mkdirs 区别如下 mkdirs 可以建立多级文件夹 mkdir 只会建立一级的文件夹 如下 new File tmp one two three mkdirs 执行后 会建立tmp one two three四级目录 n
  • 算法:回文字符串

    要求 给定一个字符串数组 判断出所有的回文字符串 class Solution public List
  • 预备打工人之SystemC学习 (五) 事务级建模库

    预备打工人之SystemC学习 TLM2 0基本概念 松散定时建模 近似定时模型 近似定时建模和松散定时建模的使用 发起者 目标 套接字和桥 DMI和调试传送结构 合并接口和套接字 名字空间和头文件 通用净核类 定义 构造 赋值和析构函数
  • JS栈内存和堆内存详解

    JS变量都存放在内存中 而内存给变量开辟了两块区域 分别为栈区域和堆区域 栈像个容器 容量小速度快 堆像个房间 容量较大 一 基本数据类型和引用数据类型存储方式 js中的数据类型可以分为基本类型和引用类型 基本类型是存在栈内存中的 引用类型
  • 在网页的JS中注入Hook

    在网页的JS中注入Hook Chrome浏览器的overrides的使用 itcoder cn 1 以下为Edge 的示例 1 本地新建一个目录 2 用浏览器关联该目录 选择目录后 浏览器上方会弹出一个横条提示确认 点击允许后即可关联 3
  • Java实现MD5加密及解密的代码实例分享

    原文地址 http www jb51 net article 86027 htm 如果对安全性的需求不是太高 MD5仍是使用非常方便和普及的加密方式 比如Java中自带的MessageDigest类就提供了支持 这里就为大家带来Java实现
  • muduo net库学习笔记4——事件驱动循环EventLoop、runInLoop和queueInLoop及对应唤醒

    首先总体情况 每个muduo网络库有一个事件驱动循环线程池 EventLoopThreadPool 线程池用在事件驱动循环上层 也就是事件驱动循环是线程池中的一个线程 每个TcpServer对应一个事件驱动循环线程池 每个线程池中有多个事件
  • jupyter notebook新建python3空白_jupyter notebook 启动出现404 302,web空白页无反应

    原来装过官网的python2 7和3 6 在这基础上装了anaconda3 启动jupyter notebook时出现404和302 复制url到猎豹和IE浏览器都没有反应 token复制也不行 后来卸载了官网的python2 7和3 6也
  • 区块链基础:交易模型解读

    1 比特币系统UTXO解读 UTXO unspent transaction output 未花费的交易输出 这是比特币交易中核心概念 UTXO是比特币拥有者的公钥锁定的一个数字 实际是是拥有者的公钥加密的数字 只有拥有者的私钥才能解开 U
  • go语言常用标准库(Time)

    go语言常用标准库 Time 1 Time 时间和日期是我们编程中经常会用到的 本文主要介绍了Go语言内置的time包的基本用法 1 1 1 time包 time包提供了时间的显示和测量用的函数 日历的计算采用的是公历 1 1 2 时间类型
  • 线性代数的本质(十一)——复数矩阵

    文章目录 复数矩阵 附录 极大线性无关组 向量叉积 复数矩阵 矩阵 A A A 的元素 a i j
  • 斐波那契数列的递归与非递归

    斐波那契数列 F n 1 n 0 1时 F n F n 1 F n 2 n gt 1时 1 递归实现 int Fib int n if n 1 n 0 return 1 return Fib n 1 Fib n 2 时间复杂度 O 2 n
  • idea常用的快捷键和常用设置

    目录 1 常用idea快捷键 2 查找相关快捷键 3 常用项目快捷键 设置字体 字体文本设置 切换主题 字符编码设置 IDEA模板 idea 目录分层 1 常用idea快捷键 1 全选 CTRL A 最简单 几乎所有的编辑器都有此功能 2
  • UISearchBar 和 UISearchDisplayController的使用

    之前比較少用UISearchBar 和 UISearchDisplayController 最近閱讀了一些有關資料 簡單做個筆記 1 UISearchBar 和 UISearchDisplayController 在IB中是可以直接使用的
  • Xshell连接VMware CentOS7

    https blog csdn net weixin 43593086 article details 90247751
  • Android屏幕适配

    一 一些概念的理解 屏幕尺寸 屏幕的对角线 如一台小米电视49寸说的就是电视对角线长度是49寸 1英寸 2 54厘米 分辨率 1920 1080指纵向1920个像素点 横向1080个像素点 1280 720同理 屏幕像素密度 DPI
  • 跟我说回家,却还在外面鬼混,python程序员教你用微信给对方定位

    跟我说回家 却还在外面鬼混 其实很多情侣之间存在很多这样的信任问题 不相信他 去查岗 可能会恶化两人之间的关系 比如跟我说回家了 但是想知道他是否真的回家了 打电话 打视频查岗吗 今天教大家一个利用微信来给对方定位的黑科技 实现方法 其实实
  • python连接clickhouse,并实现对表内数据的增删改查

    基本信息 clickhouse 基本介绍可以参考 https clickhouse com docs zh python 连接 clickhouse 可以参考 https clickhouse com docs en integration
  • 网络 链路层

    数据链路层是计算机网络的底层 主要负责相邻设备之间的数据帧传输 链路层就是负责每一个相邻结点之间的数据传输 但是相邻设备之间也需要描述识别 主要是因为每一个设备都有可能有多个相邻的设备 这种识别在链路层中是通过MAC地址来实现的 MAC地址
  • C++ 类型转换

    文章目录 c语言中的类型转换 为什么C 需要四种类型转换 C 强制类型转换 static cast reinterpret cast const cast dynamic cast c语言中的类型转换 在C语言中 如果赋值运算符左右两侧类型