news 2026/4/3 5:29:01

【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/1 8:50:43

哔哩下载姬DownKyi完整教程:B站视频下载终极指南

哔哩下载姬DownKyi完整教程&#xff1a;B站视频下载终极指南 【免费下载链接】downkyi 哔哩下载姬downkyi&#xff0c;哔哩哔哩网站视频下载工具&#xff0c;支持批量下载&#xff0c;支持8K、HDR、杜比视界&#xff0c;提供工具箱&#xff08;音视频提取、去水印等&#xff09…

作者头像 李华
网站建设 2026/4/3 4:30:27

Qwen3-1.7B-FP8震撼发布:轻量化开源大模型开启高效AI应用新纪元

Qwen3-1.7B-FP8震撼发布&#xff1a;轻量化开源大模型开启高效AI应用新纪元 【免费下载链接】Qwen3-1.7B-FP8 Qwen3-1.7B的 FP8 版本&#xff0c;具有以下功能&#xff1a; 类型&#xff1a;因果语言模型 训练阶段&#xff1a;训练前和训练后 参数数量&#xff1a;17亿 参数数量…

作者头像 李华
网站建设 2026/3/31 8:59:51

Wan2.2-T2V-A14B在动物行为模拟视频中的生物力学合理性

Wan2.2-T2V-A14B在动物行为模拟视频中的生物力学合理性 当一只猎豹在草原上追逐羚羊&#xff0c;它的脊柱如何伸展&#xff1f;前肢蹬地时肌肉的发力顺序是怎样的&#xff1f;这些细节不仅关乎画面是否“看起来真实”&#xff0c;更决定了生成内容能否被用于科学研究。在过去&a…

作者头像 李华
网站建设 2026/4/1 0:29:42

选择采购单按钮

edit.nvue<div class"detail-orders-button active" click"toOrders">选择采购单 </div>onload(pms){// 接收并存储menuId和idMenuDTO}methosd&#xff1a;{toOrders&#xff08;&#xff09;{// 1) 检查是否选择了供应商// 2) 检查是否选择了…

作者头像 李华
网站建设 2026/3/27 17:57:14

小程序怎么做?3 种制作方式 + 费用明细,低成本快速落地

一、小程序制作的 3 种核心方式&#xff1a;步骤与适配场景 &#xff08;一&#xff09;自研开发&#xff1a;技术主导&#xff0c;灵活度拉满适合具备技术团队、需求高度个性化的企业&#xff0c;核心步骤遵循微信官方标准流程&#xff1a; 准备阶段&#xff1a;登录微信公众平…

作者头像 李华