C++四种cast操作符

本文介绍了C++中的四种类型转换操作符:reinterpret_cast、const_cast、static_cast和dynamic_cast的使用方法及注意事项。这些操作符提供了不同的类型转换能力,从简单的二进制拷贝到复杂的运行时类型检查。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C 风格(C-style)强制转型如下:

(T) expression  

T(expression) //函数风格(Function-style

两种形式之间没有本质上的不同。

对于具有转换的简单类型而言C 风格转型工作得很好。然而,这样的转换符也能不分皂白地应用于类(class)和类的指针。ANSI-C++标准定义了四个新的转换符:reinterpret_cast, static_cast, dynamic_castconst_cast目的在于控制类(class)之间的类型转换。

1.1       reinpreter_cast

用法:reinpreter_cast<type-id> (expression)

type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。

这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。reinpreter_cast是特意用于底层的强制转型,导致实现依赖(就是说,不可移植)的结果。

int n=9;

// reinterpret_cast 仅仅是复制 n 的比特位到 d,因此d 包含无用值。

double d=reinterpret_cast<double & > (n);

1.2       const_cast

用法:const_cast<type_id> (expression)

用于修改类型的constvolatile属性。除了const volatile修饰之外,type_idexpression的类型是一样的,一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型,而C不提供消除const的机制(已验证)。

常量指针被转化成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

1.3       static_cast

用法:static_cast < type-id > ( expression )

该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它允许执行任意的隐式转换和相反转换动作。主要有如下几种用法:

1)用于基本数据类型之间的转换,如把int转换成charnon-const 对象转型为 const 对象(这里相反方向不可以,C++只有const_cast可以)。

2)把空指针转换成目标类型的指针。(之前的做法是用强制转换(type-id*)

3)把任何类型的表达式转换成void类型。

4)应用到类的指针上,它允许子类类型的指针转换为父类类型的指针(upercasting这是一个有效的隐式转换);也能够执行相反动作,即转换父类为它的子类(downcasting),这种转换的安全性需要开发人员来保证(主要是在非上下转型中)。

class Base {};

class Derived : public Base {};

Base *a = new Base;

Derived *b = NULL;

b = static_cast<Derived *>(a); //可以通过编译,但存在安全隐患(如访问//Derived的成员)

注意:

1static_cast不能转换掉expressionconstvolitale、或者__unaligned属性。

2.在非基本类型或上下转型中,被转换的父类需要检查是否与目的类型相一致,否则,如果在两个完全不相干的类之间进行转换,将会导致编译出错。

1.4       dynamic_cast

只用于对象的指针和引用,主要用于执行“安全的向下转型”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。

当用于多态类型时(包含虚函数),它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(即隐式转换的相反过程),dynamic_cast根据RTTI信息检查操作是否有效。即在转换时dynamic_cast会检查转换是否能返回一个被请求的有效的完整对象。这种检查不是语法上的,而是真实情况的检查。检测在运行时进行,如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL

先看RTTI相关部分,通常,许多编译器都是通过vtable找到对象的RTTI信息的,这也就意味着,如果基类没有虚函数,也就无法判断一个基类指针变量所指对象的真实类型, 这时候dynamic_cast只能用来做安全的转换(upercasting,如从派生类指针转换成基类指针,而这种转换其实并不需要dynamic_cast参与。

class Base { virtual dummy() {} };

class Derived : public Base {};

class Other{} ;

Base* b1 = new Derived;

Base* b2 = new Base;

Derived* d1 = dynamic_cast<Derived *>(b1);  // succeeds

Derived* d2 = dynamic_cast<Derived *>(b2);  // fails: returns 'NULL'

//如果一个引用类型执行了类型转换并且这个转换是不可能的,运行时一个//bad_cast的异常类型会被抛出:

Derived d3 = dynamic_cast<Derived &>(*b1);  // succeeds

Derived d4 = dynamic_cast<Derived &>(*b2);  // fails: exception thrown

注意:Base需要有虚函数,否则会编译出错。

1.5       小结

四种类型转换操作符对于隐式的类型转换没有必要。

static_cast在更宽上范围内可以完成映射,这种不加限制的映射伴随着不安全性。在类层次间进行上行转换时,dynamic_caststatic_cast的效果是一样的;在进行下行转换时(基类需要包含虚函数),dynamic_cast具有类型检查的功能,牺牲了效率,但比static_cast安全。

### 关于四种 Cast 操作符的功能及用法 C++ 提供了四种显式的类型转换操作符:`static_cast`, `dynamic_cast`, `reinterpret_cast`, 和 `const_cast`。每种类型的用途和适用场景都有所不同。 #### 1. **Static Cast** `static_cast` 是一种通用的强制类型转换工具,适用于大多数常见的类型转换情况。它可以执行隐式类型转换以及一些额外的操作,例如基础数据类型之间的转换、枚举到整数的转换等[^3]。 它还可以用于用户定义类型的转换,前提是这些转换可以通过构造函数或转换运算符实现[^1]。然而,需要注意的是,`static_cast` 并不会在运行时验证指针的实际类型安全性,因此如果错误使用可能会导致未定义行为。 ```cpp double d = 3.14; int i = static_cast<int>(d); // 将 double 转换为 int class Base {}; class Derived : public Base {}; Base* basePtr = new Derived(); Derived* derivedPtr = static_cast<Derived*>(basePtr); // 子类转父类的安全转换 ``` --- #### 2. **Dynamic Cast** `dynamic_cast` 主要用于涉及继承层次结构中的指针或引用的向下转型(即从基类向派生类的转换)。它的特点是能够在运行时检查目标类型的合法性,从而提供更高的安全性[^2]。当尝试将一个基类指针转换为其实际指向的具体子类时,如果没有匹配的对象,则返回空指针(对于指针而言),或者抛出异常(对于引用而言)。 ```cpp class Base { public: virtual ~Base() {} }; class Derived : public Base {}; Base* basePtr = new Base(); // 如果 basePtr 实际上并不指向 Derived 类型对象,则结果为空 Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); if (!derivedPtr) { std::cout << "Conversion failed!" << std::endl; } ``` 注意:只有存在虚函数的情况下才能支持这种动态检测机制,因为这依赖 RTTI(Run-Time Type Information)的支持[^2]。 --- #### 3. **Reinterpret Cast** 与其他三种相比,`reinterpret_cast` 更加危险也更强大。它允许程序员完全重新解释内存布局的意义——即使这意味着跨越完全不同类别之间毫无关联的数据形式。由于缺乏任何种类的形式化保障措施来确认此类转变是否合理合法,所以应该谨慎对待并仅限特殊场合下才考虑采用这种方法[^5]。 ```cpp int value = 42; float* floatPtr = reinterpret_cast<float*>(&value); // 危险做法!直接改变数值意义 std::cout << *floatPtr << std::endl; // 输出可能不符合预期 ``` > 特别提醒:除非绝对必要且充分理解后果之后再决定运用此手段外,在日常开发过程中应尽量避免利用 reinterprete_cast 进行处理工作。 --- #### 4. **Const Cast** 最后介绍的是 `const_cast` ,专门用来移除变量常量属性或将非常量赋给带 const 或 volatile 修饰限定词的目标位置。尽管如此简单明了的设计初衷良好,但在实践中却容易引发潜在隐患,尤其是当我们试图修改那些原本设计成只读访问权限的内容时候更是如此[^4]。 ```cpp const int ci = 10; int& ref = const_cast<int&>(ci); // 移除了 'const' 属性 ref = 20; std::cout << ci << std::endl; // 结果可能是不确定的行为 ``` 以上就是有关 C++ 中四大 cast 操作符各自特点及其典型应用场景概述说明文档内容总结完毕! ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值