news 2026/4/16 12:57:30

【C++】--- 类型转换

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【C++】--- 类型转换

Welcome to 9ilk's Code World

(๑•́ ₃ •̀๑)个人主页:9ilk

(๑•́ ₃ •̀๑)文章专栏: C++


本篇博客主要是对C/C++中类型转换的梳理总结。

内置类型转换

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

1. 隐式类型转换:编译器在编译阶段自动进行,能转就转,不能转就编译失败,通常是在整形之间/整形和浮点数之间。

2. 显示类型转换:需要用户自己处理,通常是在指针和整形、指针之间发生。

//隐式类型转换 整形家族 整形与浮点型 size_t t = 21; double d = 21; printf("%d,%f\n", t, d); //强制类型转换 不同类型的指针之间 指针与整形 double* pd = &d; int* pi = (int*)pd; int o = (int)pi;

我们可以看到,对于这两种类型转换,转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换。

内置类型转换为自定义类型

内置类型转换为自定义类型,需要在自定义类型提供对应的构造函数,这样才能进行单参和多参的隐式类型转换,此时会产生临时对象,再用这个临时对象构造(编译器不优化时):

class A { public: A(int a) :_a1(a) , _a2(a) { cout << "A(int a)" << endl; } A(int a1, int a2) :_a1(a1), _a2(a2) { cout << "A(int a1, int a2)" << endl; } A(const A&) { cout << "A(const A&)" << endl; } private: int _a1 = 1; int _a2 = 1; }; int main() { //单参和多参的隐式类型转换 A aa1 = 1; A aa2 = {1,2}; const A& aa3 = {2,2};//隐式类型产生临时对象 return 0; }

自定义类型转为内置类型

自定义类型可以通过内置类型转换为内置类型,需要注意的是operator 类型(类型转换符)实现,是没有返回类型的:

class B { public: B() {} operator int() { return _a1 + _a2; } private: int _a1 = 1; int _a2 = 1; }; int main() { B b1; int x = b1.operator int(); int y = b1; return 0; }

我们可以看到语法层面不管你是否显示调用operator int,底层都是转换成函数调用:

对于y这种其实是隐式类型转换的写法,我们可以用explicit关键字验证下,它能让禁止编译器禁止隐式类型转换:

自定义类型之间的转换

类型转换之间需要关联性,之前的显示和隐式就是关联性强弱的问题,这里自定义类型之间的转换也一样,需要对应构造函数支持:

class A { public: A(int a) :_a1(a) , _a2(a) { cout << "A(int a)" << endl; } A(int a1, int a2) :_a1(a1), _a2(a2) { cout << "A(int a1, int a2)" << endl; } A(const A&) { cout << "A(const A&)" << endl; } int get() const { return _a1 + _a2; } private: int _a1 = 1; int _a2 = 1; }; class B { public: B() {} B(const A& aa) :_a1(aa.get()) { cout << "B(const A& aa)" << endl; } explicit operator int() { return _a1 + _a2; } private: int _a1 = 1; int _a2 = 1; }; int main() { A aa1(1); B bb1 = aa1; const B& ref = aa1; return 0; }

下面我们看这样的一个场景:

typedef _list_iterator<T,T&,T*> iterator; typedef _list_iterator<T,const T&,const T*> const_iterator; zlist::list<int> it = {1,2,3,4}; zlist::list<int>::const_iterator cit = it.begin();

这里将一个普通迭代器赋值给const迭代器类型,这里会报错,但是注意报错原因不是权限缩小,因为只有指针引用采用权限问题,这里的原因是两种迭代器是同一个类模板参数传不同的模板参数产生的不同类型,因此这里it对应的是普通迭代器,与const迭代器类型不匹配,也就是说,这里其实是个类型转换问题。

此时就可以函数来实现自定义类型之间的转换,我们需求是普通迭代器转换成const迭代器,因此我们写个对应的构造函数即可,当传参传的是普通迭代器时,这里相当于是个普通构造函数:

ListIterator(const ListIterator<T, T&, T*>& it) :_node(it._node) { cout << "ListIterator(const ListIterator<T, T&, T*>& it)" << endl; }

C++中的类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符: static_cast、reinterpret_cast、const_cast、dynamic_cast

static_cast

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

int a = 20; double d = static_cast<int>(a); //对标隐式类型转换

reinterpret_cast

reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型,用于两个不相关类型之间的转换:

int* pa = &a; double* pd = reinterpret_cast<double*>(pa);//对标显示类型转换

const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值,它对应的是强制类型转换中有风险的去掉const属性:

const int a = 2; int* p = (int*)&a; int* p2 = const_cast<int*>(&a); *p = 3;

我们打印看下结果:

cout << a << endl; //2 cout << *p2 << endl; //3

由于a本身是const int,因此在编译期就把它优化为一个立即数2,不再去内存里取值,此时我们要想它读的是最新的,可以加上volatile关键字修饰,告诉编译器每次从内存中读取最新的:

volatile const int a = 2; int* p = (int*)&a; int* p2 = const_cast<int*>(&a);

dynamic_cast

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

  • 向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
  • 向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的),毕竟子类比父类多一部分成员的话,你访问会造成越界

注意:

1. dynamic_cast只能用于父类含有虚函数的类,因为运行时类型检测需要运行时的类型信息,而这个信息是存储在虚函数表中的,只有定义了虚函数的类才有虚函数表。

2. dynamic_cast会先检查是否能转换成功,能成功(pc指向子类对象)则转换,不成功(pc指向父类对象)则返回NULL

class A { public: virtual void f() {} int _a = 1; }; class B : public A { public: int _b = 2; }; void fun(A* pa) { // dynamic_cast会先检查是否能转换成功(指向子类对象),能成功则转换, // (指向父类对象)不能则返回NULL B* pb1 = dynamic_cast<B*>(pa); if (pb1) { cout << "pb1:" << pb1 << endl; cout << pb1->_a << endl; cout << pb1->_b << endl; pb1->_a++; pb1->_b++; cout << pb1->_a << endl; cout << pb1->_b << endl; } else { cout << "转换失败" << endl; } } int main() { A a; B b; fun(&a); fun(&b); return 0; }

注意:

强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是 否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用 域,以减少发生错误的机会。强烈建议:避免使用强制类型转换。

RTTI

RTTI:Run-time Type identification的简称,即:运行时类型识别。

C++通过以下方式来支持RTTI:

1. typeid运算符

2. dynamic_cast运算符

3. decltype

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 0:13:58

医疗健康AI Agent:开发难点与突破

医疗健康AI Agent&#xff1a;开发难点与突破关键词&#xff1a;医疗健康、AI Agent、开发难点、技术突破、医疗应用摘要&#xff1a;本文聚焦于医疗健康AI Agent的开发&#xff0c;深入探讨了其在医疗领域应用的背景、核心概念、算法原理、数学模型等方面的内容。详细分析了开…

作者头像 李华
网站建设 2026/4/14 15:45:02

阿里云Qwen3重大版本革新:分离式训练技术引领开源大模型性能突破

2025年7月21日&#xff0c;阿里云通义千问团队在AI领域投下重磅炸弹——正式发布Qwen3系列的里程碑版本Qwen3-235B-A22B-Instruct-2507-FP8。这款经过全面升级的旗舰模型不仅在核心性能指标上超越了Kimi-K2、DeepSeek-V3等当前开源领域的标杆产品&#xff0c;更在部分关键能力上…

作者头像 李华
网站建设 2026/4/5 12:14:57

iOS微信红包助手2025:智能自动抢红包完全指南

iOS微信红包助手2025&#xff1a;智能自动抢红包完全指南 【免费下载链接】WeChatRedEnvelopesHelper iOS版微信抢红包插件,支持后台抢红包 项目地址: https://gitcode.com/gh_mirrors/we/WeChatRedEnvelopesHelper 还在为错过微信红包而烦恼吗&#xff1f;2025年最先进…

作者头像 李华
网站建设 2026/4/16 2:56:50

市场运营年终PPT生成效率榜:AI工具真实体验排名

每到年终&#xff0c;市场运营的小伙伴们就忙得不可开交&#xff0c;尤其是制作年终总结PPT&#xff0c;简直是一场噩梦。要熬夜搜集资料、搭建框架&#xff0c;好不容易有了内容&#xff0c;又得为设计美观度发愁&#xff0c;而且不同软件之间还存在格式兼容问题&#xff0c;一…

作者头像 李华
网站建设 2026/4/15 15:12:06

Wan2.2-T2V-A14B如何生成带有文字标题的动态片头?

Wan2.2-T2V-A14B如何生成带有文字标题的动态片头&#xff1f; 在短视频日更、品牌内容全球分发的今天&#xff0c;一个高质量的动态片头早已不是影视工业的专属配置。无论是教育博主需要为每期节目定制“知识星球”开场动画&#xff0c;还是跨国企业要快速输出十种语言版本的品…

作者头像 李华