【C++】C++的类型转换--详解

一.C语言的类型转换

在 C 语言里,当赋值运算符两边类型不一致、形参和实参类型不匹配、或者函数返回值与接收变量类型不一样时,就会触发类型转换。

C 语言的类型转换分为两种:隐式类型转换与显式类型转换。

  • 隐式类型转换:由编译器在编译期间自动完成,可以转换就执行转换,无法转换则直接编译报错。
  • 显式类型转换:需要程序员手动编写代码完成转换。

来看代码:

cpp 复制代码
#include <stdio.h>

void Test ()
{
    int i = 1;
    // 隐式类型转换:int自动转为double
    double d = i;
    printf("%d, %.2f\n" , i, d);
 
    int* p = &i;
    // 显式强制类型转换,把指针地址转为整型
    //注意:指针转int存在平台风险,64位下建议用uintptr_t
    int address = (int) p;
 
    printf("%p, %d\n" , p, address);
}

int main(void)
{
    Test();
    return 0;
}

C语言强转缺陷:转换的可视性较差,所有转换都写成同一种形式,很难定位出错的类型转换,不利于跟踪错误。


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

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

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

因此 C++ 提出了自己的类型转化风格,注意因为 C++ 要兼容 C 语言,所以 C++ 中还可以使用 C 语言的转化风格。


三.C++ 强制类型转换

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

  • static_cast(普通静态类型转换)
  • reinterpret_cast(二进制重新解释转换)
  • const_cast(修改常量属性)
  • dynamic_cast(多态安全向下转换,运行校验)

1.static_cast

static_cast 适用于非多态类型之间的静态转换。凡是编译器能够自动隐式完成的类型转换,都可以使用 static_cast 显式写出;但它不支持两个毫无关联的类型相互转换。

cpp 复制代码
#include <iostream>
using namespace std;

int main()
{
    double d = 12.34;
    // 把double转为int,属于相近类型转换,static_cast合法
    int a = static_cast<int>(d);
    cout << a << endl;

    return 0;
}

double 向 int 转换属于合法的数值类型转换,static_cast 在编译阶段完成转换,直接舍弃小数部分,输出 12。static_cast 不支持无关类型(如指针与 int)的转换。


2.reinterpret_cast

reinterpret_cast 会直接对数据的二进制位重新解读,适合把一种完全不同的类型转换成另一种类型,不做类型安全性检查。

**注意:**这种转换仅仅改变类型解释方式,不会修改内存里的二进制内容,风险很高。

cpp 复制代码
#include <iostream>
using namespace std;

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

    // static_cast不支持整型向指针转换,编译报错
    //int *p = static_cast<int*>(a);
    //强行把整型数值解释成指针地址
    int *p = reinterpret_cast<int*>(a);

    return 0;
}

整型与指针是无关类型,static_cast 不支持转换。reinterpret_cast 直接将 a 中的数值解读成指针地址,仅改变类型视角,不改动二进制数据。该转换语法可行,但得到的是无效地址,不要对指针解引用,风险较大。


3.const_cast

const_cast 主要用来移除或者增加变量的 const 属性,最常见用法是去掉 const 限定。

**注意:**它不是真正消除常量本身的只读属性,只是修改指针 / 引用的类型;如果原本是常量,强行修改会出现未定义行为。

cpp 复制代码
#include <iostream>
using namespace std;

void Test()
{
    const int a = 2;
    //去掉const属性,用普通指针接收常量的地址
    int* p = const_cast<int*>(&a);
    *p = 3;
    cout << a << endl;
}

int main()
{
    Test();
    return 0;
}

普通指针无法接收 const 变量的地址,借助 const_cast 去除指针的 const 限制。但 a 本身是常量,通过指针修改常量属于未定义行为,运行结果不确定。const_cast 仅能增减 const 属性,不支持其他类型转换。

补充实用场景:它更适合本来不是常量,只是被 const 指针接收的情况,这种修改是安全的。如果你想要,我可以写一段安全使用 const_cast 的示例。


4.dynamic_cast

dynamic_cast 用来完成父类指针或引用向子类指针或引用的动态转换。

  • 向上转型:子类指针 / 引用转为父类指针 / 引用,依靠赋值兼容规则,不需要强制转换。
  • 向下转型:父类指针 / 引用转为子类指针 / 引用,使用 dynamic_cast 可以实现安全转换。

注意: dynamic_cast 只能用在包含虚函数的父类中。 转换时它会先做运行时检查,如果转换合法就正常转换;转换失败,指针会返回空指针 0。

cpp 复制代码
#include <iostream>
using namespace std;

class A
{
public:
    virtual void f() {}
};

class B : public A
{
};

void fun(A* pa)
{
    B* pb1 = static_cast<B*>(pa);
    B* pb2 = dynamic_cast<B*>(pa);

    cout << "pb1:" << pb1 << endl;
    cout << "pb2:" << pb2 << endl;
}

int main()
{
    A a;
    B b;
    fun(&a);
    fun(&b);
    return 0;
}
  1. A 类中写了虚函数,这是 dynamic_cast 能够正常使用的前提。
  2. 第一次调用 fun (&a),传进去的是父类对象地址。 static_cast 不会在运行时校验对象真实类型,直接强制转为 B 类指针,拿到的指针是无效的; dynamic_cast 运行时检测出原始对象是父类,向下转换行不通,直接返回空指针。
  3. 第二次调用 fun (&b),传入子类对象地址。 两种转换都能成功得到子类指针。
  4. static_cast 只在编译期间做简单检查,向下转型存在安全隐患;dynamic_cast 依靠运行时类型判断保证安全,多用于多态代码。

补充:强制类型转换会跳过常规的类型检查。写代码时,优先想想有没有不用强制转换的方案。实在不得不使用强制转换,尽量缩小它的作用范围,减少 bug 出现的可能性。


四.RTTI(了解)

RTTI:Run-time Type identification 的缩写,即运行时类型识别,用来在程序运行阶段判断对象的真实类型。

C++ 通过下面几个方式支持 RTTI:

  • typeid 运算符:返回一个 type_info 对象,用来查询表达式的实际类型。
  • dynamic_cast 运算符:前面讲过,用于多态下安全向下转型,能转就转,不能转返回空指针。
  • decltype:在编译阶段推导表达式的类型,主要配合模板和泛型编程使用。
    补充:RTTI 需要依赖虚函数表来记录类型信息,所以想要用 RTTI 判断类型,前提是类里面包含虚函数

通俗理解就是:typeid 负责 "看是什么类型",dynamic_cast 负责 "能不能安全转",decltype 则偏编译期推导,三者应用场景不太一样。

相关推荐
倒头就睡的小比特5 天前
算法竞赛C++常用的STL
c++·算法
weilx12345 天前
C++笔记-文件IO-<fcntl.h>
c++
Smileyqp沛沛5 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车5 天前
C/C++ 为什么需要编译器?
开发语言·c++
旖旎夜光5 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
吞下星星的少年·-·5 天前
C++ 萌新语法入门篇
c++·算法比赛
霍霍的袁5 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
another heaven5 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
程序猿编码5 天前
告别改源码适配模型:纯 C++ 可配置 LLM 推理引擎,全格式全结构兼容
c++·大模型·llm·推理引擎
此生决int5 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++