当前位置: 首页 > news >正文

【c++】四种类型转换形式

【c++】四种类型转换形式

编译时:
static_cast(静态转换)
const_cast(去常性转换)
reinterpret_cast(重新解释转换,直接转换地址)
运行时:
dynamic_cast(动态转换,运行时类型识别 RTTI)


static_cast(静态转换)

用途描述注意事项
基本数据类型之间的转换用于 int → doublechar → int 等数值类型之间的转换。适用于已知类型的转换,比 C 风格转换更安全。
void* 转换为其他类型void* 指针还原为具体类型的指针。必须确保指针类型正确,否则会导致未定义行为。
左值转换为右值将左值转换为右值引用,常用于移动语义。强制转换为右值引用,可触发移动构造函数。
类型层次结构中的指针和引用转换在继承关系中,基类和派生类之间的指针或引用转换。向上转换安全,向下转换需用 dynamic_cast 来保证运行时安全。
int 类型转换为枚举允许 int 与枚举类型之间的相互转换。适用于整数到枚举的安全转换,但要确保值在枚举范围内。
模板中的应用在模板编程中确保目标类型和原始类型一致,并进行类型转换。可结合 static_assert 进行编译期类型检查,提高泛型代码的安全性。
1. 基本数据类型转换

static_cast 可用于基本数据类型之间的转换,如 intdoublecharint,等价于 C 风格转换,但更安全。

#include <iostream>int main() {double d = 3.14159;int i = static_cast<int>(d);  // 截断小数部分,转换为 3char c = 'A';int ascii = static_cast<int>(c);  // 将字符 'A' 转换为 ASCII 码std::cout << "i = " << i << ", ascii = " << ascii << std::endl;return 0;
}

优点:比 C 风格转换更安全,可读性更好,避免了 reinterpret_cast 的风险。


2. void* 转换为其他类型

static_cast 可以用于void* 还原为具体类型,但必须确保指针类型正确,否则可能导致未定义行为。

#include <iostream>int main() {int a = 42;void* pVoid = &a;  // int* → void*int* pInt = static_cast<int*>(pVoid);  // void* → int*std::cout << "pInt = " << *pInt << std::endl;return 0;
}

适用于已知原始类型的情况,如果不确定类型,应使用 reinterpret_cast


3. 左值转换为右值

在 C++11 及更高版本中,static_cast 可以将左值转换为右值引用,用于移动语义

#include <iostream>
#include <utility>  // std::moveclass Data {
public:Data() { std::cout << "构造函数\n"; }Data(const Data&) { std::cout << "拷贝构造\n"; }Data(Data&&) { std::cout << "移动构造\n"; }
};int main() {Data d;Data d2 = static_cast<Data&&>(d);  // 强制转换为右值引用,触发移动构造return 0;
}

std::move 类似,但 static_cast<Data&&> 是显式的转换方式


4. 类型层次结构中的指针和引用转换

类的继承关系中,static_cast 可以在基类和派生类之间进行转换,但仅限安全的向上转换

#include <iostream>class Base {
public:virtual void show() { std::cout << "Base 类\n"; }
};class Derived : public Base {
public:void show() override { std::cout << "Derived 类\n"; }
};int main() {Derived d;Base* pBase = static_cast<Base*>(&d);  // 向上转换pBase->show();  // 仍然调用 Derived 的 `show()`return 0;
}

⚠️ 向下转换(Base*Derived*)是不安全的,需要用 dynamic_cast


5. int 类型转换为枚举

static_cast 允许整数和枚举类型之间的转换

#include <iostream>enum Color { RED, GREEN, BLUE };int main() {int num = 1;Color c = static_cast<Color>(num);  // 将 int 转换为枚举类型std::cout << "c = " << c << std::endl;return 0;
}

适用于整数到枚举的安全转换


6. static_cast 在模板中的应用

在模板编程中,可以使用 static_cast 确保目标类型和原始类型一致

#include <iostream>
#include <type_traits>template <typename T, typename U>
T convert(U value) {static_assert(std::is_convertible<U, T>::value, "类型不兼容!");return static_cast<T>(value);
}int main() {double d = 3.14;int i = convert<int>(d);  // double → intstd::cout << "i = " << i << std::endl;return 0;
}

static_assert 可用于编译期检查类型是否可以转换


const_cast(去常性转换)

特点描述
只能对同类型使用const_cast 类型必须相同。
不能用于基本数据类型不能用于基本数据类型之间的转换(例如:int → double)。
转换目标为指针或引用只能将指针或引用的常量属性去除,而不能作用于值类型。

常量指针/引用被转换为非常量的指针/引用,并仍然指向原来的对象

例子:

1.常量指针转为非常量指针

#include <iostream>void modifyValue(const int* ptr) {// const_cast 去常性转换int* modifiablePtr = const_cast<int*>(ptr);*modifiablePtr = 20;  // 可以修改原对象
}int main() {const int a = 10;modifyValue(&a);  // 将常量指针转换为非常量指针return 0;
}

2.常量引用转为非常量引用

#include <iostream>void modifyValue(const int& ref) {// const_cast 去常性转换int& modifiableRef = const_cast<int&>(ref);modifiableRef = 20;  // 可以修改原对象
}int main() {const int a = 10;modifyValue(a);  // 将常量引用转换为非常量引用return 0;
}
注意事项:
  • const_cast 只会移除常量属性,并不会改变对象本身。
  • 对于常量对象的修改仍然是未定义行为,因此不应使用 const_cast 去修改那些原本是常量的数据。

reinterpret_cast(重新解释转换)

是 C++ 中最危险的类型转换之一,它将数据从一种类型“强制”转换为另一种类型,并且不进行任何类型检查。
它是按解释的

特点描述
最危险的转换reinterpret_cast 不进行任何类型检查,可能导致未定义行为。
按位解释转换直接基于内存的二进制表示,不考虑类型的语义。
指针之间的转换可用于不同类型的指针之间的转换。
指针与整数之间的转换可将指针转换为整数,反之亦然。
1. 指针类型转换
#include <iostream>int main() {int a = 42;// 强制将 int* 转换为 double*,危险操作,按位解释double* p = reinterpret_cast<double*>(&a);std::cout << *p << std::endl;  // 不确定行为,可能崩溃return 0;
}
2. 指针与整数转换
#include <iostream>int main() {int* p = reinterpret_cast<int*>(0x1234);  // 将整数转换为指针std::cout << "Pointer: " << p << std::endl;uintptr_t addr = reinterpret_cast<uintptr_t>(p);  // 将指针转换为整数std::cout << "Address as integer: " << addr << std::endl;return 0;
}

动态转换(dynamic_cast

是一种用于在类层次结构中进行指针或引用类型转换的操作,特别适用于下行转换(基类指针或引用转换为派生类指针或引用)。dynamic_cast运行时检查类型安全,依赖于虚函数表和运行时类型信息(RTTI),通过虚函数表中的信息来实现类型检查。

1.上行转换(向上转换)

  • 向上转换是指派生类对象转换为基类指针或引用是在编译时进行的,与静态类型转换等价,不查虚表

2.下行转换(向下转换)

  • 向下转换是指基类指针或引用转换为派生类指针或引用。这种转换在运行时需要类型检查
  • 并且只有在公有继承和继承关系中存在虚函数时才有效,否则没有运行时类型信息(RTTI)进行类型检查。
  • 使用 dynamic_cast 来进行下行转换时,转换成功时返回派生类指针或引用,转换失败时返回 nullptr(对于指针类型),或者抛出 std::bad_cast 异常(对于引用类型)。

例如

class Base {
public:virtual ~Base() {}  // 必须有虚析构函数,以支持RTTI
};class Derived : public Base {};int main() {Base* pBase = new Derived();Derived* pDerived = dynamic_cast<Derived*>(pBase);  // 成功,转换为派生类指针if (pDerived) {std::cout << "转换成功!" << std::endl;} else {std::cout << "转换失败!" << std::endl;}delete pBase;return 0;
}
  • 如果 pBase 实际上指向一个 Derived 类型对象,则 pDerived 会成功转换,并指向该对象。
  • 如果 pBase 并不指向 Derived 类型对象,dynamic_cast 将返回 nullptr,指示转换失败。
如何判断是否能够进行下行转换
  • 条件:只有当类之间存在虚函数(如虚析构函数)时,RTTI 才会被启用,dynamic_cast 才能进行类型检查。
  • 执行流程

        1.dynamic_cast 会查询对象的虚函数表(vtable)。

        2.如果查询到类型匹配,则转换成功。

        3.如果查询失败,则返回 nullptr(对于指针类型),或抛出异常 std::bad_cast(对于引用类型)。


文章转载自:

http://8c64BBVx.mdnnz.cn
http://SWAw2kS9.mdnnz.cn
http://xA6KOO4p.mdnnz.cn
http://8pQWB7yY.mdnnz.cn
http://LuuRpT7D.mdnnz.cn
http://0UgMm3sz.mdnnz.cn
http://BNJH23oo.mdnnz.cn
http://z6LDTteR.mdnnz.cn
http://Dl4BxAw6.mdnnz.cn
http://ZxcpsO0R.mdnnz.cn
http://vVmj8HZz.mdnnz.cn
http://PvseNw0y.mdnnz.cn
http://fdonZFUR.mdnnz.cn
http://jDtDy1x8.mdnnz.cn
http://FP5wbomJ.mdnnz.cn
http://koV2FFUo.mdnnz.cn
http://tJYldPL4.mdnnz.cn
http://0cvJIBQA.mdnnz.cn
http://7N2I8V1V.mdnnz.cn
http://99uyNSur.mdnnz.cn
http://qLZhUhKe.mdnnz.cn
http://YnwgQDNo.mdnnz.cn
http://BBzRhUIc.mdnnz.cn
http://1txfn2Jn.mdnnz.cn
http://Onpi5PZD.mdnnz.cn
http://CIs51qZJ.mdnnz.cn
http://ZSj9WjMl.mdnnz.cn
http://rqHI24Dh.mdnnz.cn
http://Idkg0DCc.mdnnz.cn
http://XvFj0CVf.mdnnz.cn
http://www.dtcms.com/a/364953.html

相关文章:

  • 安全、计量、远程控制,多用途场景下的智慧型断路器
  • AV1 OBU Frame解析
  • 如何在 macOS 中使用 Homebrew Cask 安装软件包 ?
  • 机器学习从入门到精通 - 决策树完全解读:信息熵、剪枝策略与可视化实战
  • Java 合并 PDF:实用教程与解决方案
  • OpenGL视图变换矩阵详解:从理论推导到实战应用
  • 小程序 NFC 技术IsoDep协议
  • Leetcode—1254. 统计封闭岛屿的数目【中等】
  • 轻轻一个字母差别,就能把首屏时间砍半——为什么90%的人还不知道?
  • 游戏总监级“AI炼金术”!Firefly+NB创造不存在的神级材质
  • 小迪web自用笔记25
  • 【第三方软件项目验收中的安全漏洞(SQL注入/XSS)修复】
  • 彩笔运维勇闯机器学习--逻辑回归
  • Day20_【机器学习—逻辑回归 (1)—原理】
  • 浅谈人工智能之阿里云搭建coze平台
  • CI(持续集成)、CD(持续交付/部署)、CT(持续测试)、CICD、CICT
  • SQL 函数:使用 REPLACE进行批量文本替换
  • 数仓实习生面试(一面)
  • Docker 安装 RAGFlow保姆教程
  • 开源 + 免费!谷歌推出 Gemini CLI,Claude Code 的强劲对手
  • UnityWebRequest 数据获取和提交
  • 深度学习-----简单入门卷积神经网络CNN的全流程
  • 异常处理小妙招——3.构造函数的安全第一原则:为什么不在构造函数中抛出异常?
  • Python爬虫实战:研究Pie and polar charts模块,构建电商数据采集和分析系统
  • 揭秘设计模式:优雅地为复杂对象结构增添新功能-访问者模式
  • 给你的应用穿上“外衣”:React中的CSS方案对比与实践
  • 【Linux】线程封装
  • 组长跟我说,她招人看重的是数据分析能力
  • 基于数据挖掘的当代不孕症医案证治规律研究
  • 从0 死磕全栈第3天:React Router (Vite + React + TS 版):构建小时站实战指南