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

【C++】C++四种类型转换操作符详解

目录

1、static_cast

2、dynamic_cast

3、const_cast

4、reinterpret_cast

实际应用


        为了解决C语言传统强制类型转换的缺陷,提供更安全、明确的语义和编译时检查,C++引入四种类型转换操作符(static_castdynamic_castconst_castreinterpret_cast),本篇文章主要介绍这四种类型转换符的使用,以及使用时需要注意的方面。

1、static_cast

编译时类型转换,比较常用,用于相关类型之间的转换。

语法:

static_cast<目标类型>(表达式)

常用示例

基本数据类型转换:

int i = 10;
double d = static_cast<double>(i);  // int转doublefloat f = 3.14f;
int j = static_cast<int>(f);        // float转int(截断小数部分)char c = static_cast<char>(65);     // int转char

类层次结构转换:

class Base { virtual ~Base() {} };
class Derived : public Base {};// 向上转换(安全)
Derived d;
Base* b = static_cast<Base*>(&d);// 向下转换(不安全,需要程序员保证正确性)
Base* basePtr = new Derived();
Derived* derivedPtr = static_cast<Derived*>(basePtr);

        类之间的转换需要注意的是,向上转换(子类向父类转换)是安全的,但是向下转换(父类向子类可能是不安全的)。

为什么向下转换是不安全的呢?

        static_cast 进行向下转换(downcasting)不安全的主要原因是 缺乏运行时类型检查 。

        编译时检查,运行时不验证,static_cast只在编译时检查类型关系是否合法,运行时不会验证对象的实际类型,如果基类指针实际指向不是目标派生类对象,编译时检查可以通过,但是结果是未定义的,如下具体demo:

class Base {
public:virtual ~Base() = default;
};class Derived1 : public Base {
public:void func1() { /* ... */ }
};class Derived2 : public Base {
public:void func2() { /* ... */ }
};// 危险的向下转换
Base* ptr = new Derived2();  // 实际指向Derived2对象
Derived1* d1 = static_cast<Derived1*>(ptr);  // 编译通过!
d1->func1();  // 未定义行为!访问了错误的对象

编译器检查流程如下:

Base* ptr = new Derived2();

这里编译器只知道:

1. ptr的静态类型是Base*

2. 赋值语句语法正确 

3. Derived2继承自Base

Derived1* d1 = static_cast<Derived1>(ptr);

这里编译器检查: 

1. ptr是Base类型

2. Derived1继承自Base

3. static_cast语法合法

        如上,这种错误的向下转换,因为static_cast是在编译期间检查静态类型关系,因此是无法识别的。

2、dynamic_cast

运行时类型检查的安全向下转换,主要用于多态类型的转换。

语法:

dynamic_cast<目标类型>(表达式)

 dynamic_cast可以保证基类指针正确的向下转换,如下:

class Base {
public:virtual ~Base() {}  // 必须有虚函数
};class Derived : public Base {
public:void derivedMethod() {}
};Base* basePtr = new Derived();// 安全的向下转换
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr != nullptr) {derivedPtr->derivedMethod();  // 转换成功
} else {// 转换失败
}

向下转换就可能存在转换成功或者转换失败的情况,转换失败时,指针返回nullptr,引用抛出bad_cast异常。

虽然dynamic_cast能够确保基类向下转换时的安全问题,但是它也付出了一些代价,运行时,开销比较大,因为要进行类型检查(查询RTTI信息),虚函数表访问等。

3、const_cast

主要用于添加或移除const、volatile限定符

语法:

const_cast<目标类型>(表达式)

适用场景

移除const限定符

const int ci = 10;
int* pi = const_cast<int*>(&ci);  // 移除const
*pi = 20;  // 危险!可能导致未定义行为// 更安全的用法
void func(const char* str) {char* modifiableStr = const_cast<char*>(str);// 只有当原始数据不是const时才安全修改
}

这里需要注意的是,不是说移除了const限定符,我们就能对这个属性进行随意修改了。

移除了const限定符,技术上可以对属性修改了,但是能否安全修改取决于原始对象是否真的是const,这里分别举安全的情况、不安全的情况的例子,方便大家理解

安全的情况

原始的对象不是const

int value = 42;  // 原始对象不是 const
const int* ptr = &value;  // 通过 const 指针访问// 使用 const_cast 移除 const,可以安全修改
int* modifiable = const_cast<int*>(ptr);
*modifiable = 100;  // ✅ 安全,因为原始对象不是 const
std::cout << value << std::endl;  // 输出: 100

不安全的情况

修改真正的const对象

const int readonly = 42;  // 真正的 const 对象
const int* ptr = &readonly;// 危险!修改真正的 const 对象
int* modifiable = const_cast<int*>(ptr);
*modifiable = 100;  // ❌ 未定义行为!// 编译器可能已经优化,认为 readonly 永远是 42
std::cout << readonly << std::endl;  // 可能仍然输出 42

添加const限定符

int i = 10;
const int* ci = const_cast<const int*>(&i);  // 添加const
  • 只能改变const/volatile限定符,不能改变类型

4、reinterpret_cast

reinterpret_cast 是最危险的类型转换,它重新解释对象的位模式,不进行任何类型检查。

语法:

reinterpret_cast<类型>(表达式)

使用示例:

类似于C语言的强转

int value = 0x12345678;
int* int_ptr = &value;// 将 int* 重新解释为 char*
char* char_ptr = reinterpret_cast<char*>(int_ptr);// 查看内存中的字节表示
for (size_t i = 0; i < sizeof(int); ++i) {printf("Byte %zu: 0x%02X\n", i, static_cast<unsigned char>(char_ptr[i]));
}

实际应用

1、实现一个安全的向下转换函数

template<typename Target, typename Source>
Target* safe_cast(Source* source) {static_assert(std::is_base_of_v<Source, Target> || std::is_base_of_v<Target, Source>,"Types must be related by inheritance");if constexpr (std::is_base_of_v<Source, Target>) {// 向下转换,使用 dynamic_castreturn dynamic_cast<Target*>(source);} else {// 向上转换,使用 static_castreturn static_cast<Target*>(source);}
}

调用方法如下:

// 可以这样调用:
int result1 = convert<int>(3.14);        // Target=int, Source=double(推导)
int result2 = convert<int, double>(3.14); // Target=int, Source=double(显式)

2、如何避免const_cast的危险

使用mutable关键字

// 使用 mutable 关键字
class Cache {
private:mutable std::unordered_map<int, std::string> cache_;
public:const std::string& get(int key) const {// 可以修改 mutable 成员if (cache_.find(key) == cache_.end()) {cache_[key] = compute_value(key);}return cache_[key];}
};// 使用函数重载
class Data {
public:const int& get() const { return value_; }int& get() { return value_; }
private:int value_;
};
http://www.xdnf.cn/news/1084537.html

相关文章:

  • 如何使用xmind编写测试用例
  • Docker容器中安装MongoDB,导入数据
  • electron中的IPC通信
  • WebRTC 的 ICE candidate 协商
  • 深度学习图像分类数据集—蘑菇识别分类
  • axios笔记
  • Monorepo+Turborepo+Next常问问题详解
  • Git使用教程
  • Win11 安装 Visual Studio(保姆教程 - 更新至2025.07)
  • 《Redis》缓存与分布式锁
  • 零基础 “入坑” Java--- 八、类和对象(一)
  • 2025.7.6总结
  • 【字节跳动】数据挖掘面试题0011:介绍下时间序列分析常用知识点
  • 9. 【Vue实战--孢子记账--Web 版开发】-- 账户账本管理(二)
  • 5种高效解决Maven依赖冲突的方法
  • C 语言指针与作用域详解
  • Clion中stm32开发烧录出现“monitor“ command not supported by this target.解决方法
  • 微服务基础:Spring Cloud Alibaba 组件有哪些?
  • 数据结构---链表结构体、指针深入理解(三)
  • nginx的使用
  • ARMv8 创建3级页表示例
  • Linux操作系统之文件(五):文件系统(下)
  • Windows ETW事件的多维度关联分析
  • Web攻防-XMLXXE无回显带外SSRF元数据DTD实体OOB盲注文件拓展
  • 【Elasticsearch】自定义评分检索
  • android 获取手机配对的蓝牙耳机的电量
  • python中生成假数据的库 faker 的详细使用,包括详细案例(生成逼真假数据)
  • Go语言实现双Token登录的思路与实现
  • 人工智能之数学基础:线性回归算法的矩阵参数求导
  • QueryWrapper 类的作用与示例详解