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

news2025/2/13 13:09:37

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

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


static_cast(静态转换)

用途描述注意事项
基本数据类型之间的转换用于 intdoublecharint 等类型之间的转换。适用于已知类型的转换,比 C 风格转换更安全。
void* 转换为其他类型用于将 void* 指针还原为具体类型的指针。必须确保指针类型正确,避免未定义行为。
左值转换为右值用于将左值转换为右值引用,常用于移动语义。强制转换为右值引用,触发移动构造。
类型层次结构中的指针和引用转换在类继承关系中,用于基类和派生类之间的转换。只能进行安全的向上转换,向下转换需要 dynamic_cast
int 类型转换为枚举允许 int 与枚举类型之间的转换。适用于整数到枚举的安全转换。
static_cast 在模板中的应用用于确保目标类型和原始类型一致,并在模板编程中进行类型转换。使用 static_assert 进行编译期类型检查。

1. 基本数据类型转换

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

#include <iostream>

int main() {
    double d = 3.14159;
    int i = static_cast<int>(d);  // 截断小数部分,转换为 3

    char 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::move

class 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 → int
    std::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://www.coloradmin.cn/o/2297378.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

半小时在本地部署DeepSeek的Janus Pro,进行图片分析和文生图

半小时在本地部署DeepSeek的Janus Pro&#xff0c;进行图片分析和文生图 下载Janus Pro源代码下载模型文件创建Python虚拟环境安装依赖包Janus Pro测试运行程序图片分析测试文生图测试使用中文提示词使用英文提示词 测试印象&#xff1a; 整体模型体积较小&#xff0c;个人可以…

急停信号的含义

前言&#xff1a; 大家好&#xff0c;我是上位机马工&#xff0c;硕士毕业4年年入40万&#xff0c;目前在一家自动化公司担任软件经理&#xff0c;从事C#上位机软件开发8年以上&#xff01;我们在开发C#的运动控制程序的时候&#xff0c;一个必要的步骤就是确认设备按钮的急停…

设置mysql的主从复制模式

mysql设置主从复制模式似乎很容易&#xff0c;关键在于1&#xff09;主库启用二进制日志&#xff0c;2&#xff09;从库将主库设为主库。另外&#xff0c;主从复制&#xff0c;复制些什么&#xff1f;从我现在获得的还很少的经验来看&#xff0c;复制的内容有表&#xff0c;用户…

三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab)

三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测&#xff08;Maltab&#xff09; 完整代码私信回复三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测&#xff08;Maltab&#xff09; 一、引言 1、研究背景和意义 在现代数据科学领域&#xff0c;时间序列…

ArcGIS基础知识之ArcMap基础设置——ArcMap选项:常规选项卡设置及作用

作为一名 GIS 从业者,ArcMap 是我们日常工作中不可或缺的工具。对于初学者来说,掌握 ArcMap 的基础设置是迈向 GIS 分析与制图的第一步。今天,就让我们一起深入了解 ArcMap 选项中常规选项卡的各个设置,帮助大家更好地使用这款强大的软件。 在 ArcMap 中,常规选项卡是用户…

14,.左下角的值,路径和,由序列确定树

找树左下角的值 迭代法 层序遍历 class Solution { public:int findBottomLeftValue(TreeNode* root) {queue<TreeNode*> qu;qu.push(root);TreeNode* leftqu.front();while(!qu.empty()){int szqu.size();leftqu.front();for(int i0;i<sz;i){TreeNode* curqu.fron…

【推理llm论文精读】DeepSeek V3技术论文_精工见效果

先附上原始论文和效果对比https://arxiv.org/pdf/2412.19437 摘要 (Abstract) DeepSeek-V3是DeepSeek-AI团队推出的最新力作&#xff0c;一个强大的混合专家&#xff08;Mixture-of-Experts&#xff0c;MoE&#xff09;语言模型。它拥有671B的总参数量&#xff0c;但每个tok…

python自动化测试之Pytest框架之YAML详解以及Parametrize数据驱动!

一、YAML详解 YAML是一种数据类型&#xff0c;它能够和JSON数据相互转化&#xff0c;它本身也是有很多数据类型可以满足我们接口 的参数类型&#xff0c;扩展名可以是.yml或.yaml 作用&#xff1a; 1.全局配置文件 基础路径&#xff0c;数据库信息&#xff0c;账号信息&…

DeepSeek 本地部署指南

在人工智能飞速发展的今天&#xff0c;大语言模型的应用越来越广泛。DeepSeek 作为一款强大的大语言模型&#xff0c;具备出色的语言理解和生成能力。然而&#xff0c;许多用户希望能够在本地部署 DeepSeek&#xff0c;以实现更高的隐私性、更低的延迟和更好的定制化。本文将为…

[LeetCode]day21 15.三数之和

题目链接 题目描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复…

Unity学习part1

课程为b站【Unity教程】零基础带你从小白到超神 1、脚本执行顺序 unity的脚本执行顺序不像blender的修改器那样按顺序执行&#xff0c;而是系统默认给配置一个值&#xff0c;值越小&#xff0c;执行顺序越靠前&#xff08;注意&#xff0c;这个顺序是全局生效的&#xff09; …

【AI论文】10亿参数大语言模型能超越405亿参数大语言模型吗?重新思考测试时计算最优缩放

摘要&#xff1a;测试时缩放&#xff08;Test-Time Scaling&#xff0c;TTS&#xff09;是一种通过在推理阶段使用额外计算来提高大语言模型&#xff08;LLMs&#xff09;性能的重要方法。然而&#xff0c;目前的研究并未系统地分析策略模型、过程奖励模型&#xff08;Process …

Ubuntu20.04上搭建nginx正向代理提供上网服务

背景&#xff1a;公司很多电脑因软件管控问题不得不禁止设备上网&#xff0c;现需搭建上网代理服务器提供给这些用户使用。 操作系统&#xff1a;ubuntu20.04 工具&#xff1a;nginx-1.25.4 1、下载nginx安装包及依赖 由于nginx默认只持支持转发http协议&#xff0c;所以如…

使用 PDF SDK 通过页面分割和数据提取对建筑图纸进行分类

一家专门从事设计和建设的建筑公司对大量多页建筑 PDF 图纸进行分类&#xff0c;从而提高协作和运营效率。 这类公司通常承担多个建筑设计项目&#xff0c;每个项目包含多个设计图纸&#xff0c;如详细的结构计划、电气与水管计划、机械计划等。如果项目图纸可以在上传后自动分…

Linux命名管道与共享内存

命名管道与共享内存 命名管道介绍和基本使用 理解了匿名管道后&#xff0c;命名管道的理解就会变得容易。在前面使用匿名管道时可以发现&#xff0c;之所以可以匿名是因为由父进程创建&#xff0c;子进程拷贝所以子进程和父进程都可以看到这个管道。但是如果对于任意两个进程…

使用 Notepad++ 编辑显示 MarkDown

Notepad 是一款免费的开源文本编辑器&#xff0c;专为 Windows 用户设计。它是替代记事本&#xff08;Notepad&#xff09;的最佳选择之一&#xff0c;因为它功能强大且轻量级。Notepad 支持多种编程语言和文件格式&#xff0c;并可以通过插件扩展其功能。 Notepad 是一款功能…

解锁Rust:融合多语言特性的编程利器

如果你曾为理解Rust的特性或它们之间的协同工作原理而苦恼,那么这篇文章正是为你准备的。 Rust拥有许多令人惊叹的特性,但这些特性并非Rust所独有。实际上,Rust巧妙地借鉴了众多其他语言的优秀特性,并将它们融合成了一个完美的整体。深入了解Rust这些重要特性的来源以及它是…

zyNo.23

SQL注入漏洞 1.SQL语句基础知识 一个数据库由多个表空间组成&#xff0c;sql注入关系到关系型数据库&#xff0c;常见的关系型数据库有MySQL,Postgres,SQLServer,Oracle等 以Mysql为例&#xff0c;输入 mysql-u用户名-p密码 即可登录到MySQL交互式命令行界面。 既然是…

visual studio 在kylin v10上跨平台编译时c++标准库提示缺少无法打开的问题解决

情况1&#xff1a;提示无法打开 源文件 "string"之类导致无法编译 情况2:能编译&#xff0c;但无法打开这些库文件或标准库使用提示下划红色问题 解决方案&#xff1a; 一、通过工具->选项->跨平台里&#xff0c;在“远程标头IntelliSense管理器”更新下载一下…

Spring Cloud — 深入了解Eureka、Ribbon及Feign

Eureka 负责服务注册与发现&#xff1b;Ribbon负责负载均衡&#xff1b;Feign简化了Web服务客户端调用方式。这三个组件可以协同工作&#xff0c;共同构建稳定、高效的微服务架构。 1 Eureka 分布式系统的CAP定理&#xff1a; 一致性&#xff08;Consistency&#xff09;&am…