【C++ 类型转换关键字 *_cast 】理解const_cast、reinterpret_cast、dynamic_cast和static_cast的用法

简介: 【C++ 类型转换关键字 *_cast 】理解const_cast、reinterpret_cast、dynamic_cast和static_cast的用法

c++除了能使用c语言的强制类型转换外,还新增了四种强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast,主要运用于继承关系类间的强制转化


cast转换符

static_cast

static_cast < type-id > ( expression )
//该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。
//它允许执行任意的隐式转换和相反转换动作.

作用:

1. 基本类型之间的转换,会损失精度,如把int转换成char,non-const 对象转型为 const 对象(这里相反方向不可以,C++只有const_cast可以)。

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

3. 用于有继承关系的子类与父类之间的指针或引用的转换

4. 把任何类型的表达式转换成void类型


特点:

  • 用于非多态类型的转换
  • 不执行运行时类型检查(转换安全性不如 dynamic_cast)
  • 通常用于转换数值数据类型(如 float -> int))
  • 可以在整个类层次结构中移动指针,子类转化为父类安全(向上转换),父类转化为子类不安全(因为子类可能有不在父类的字段或方法)

注意:

static_cast不能转换掉expression的const、volitale、或者__unaligned属性。
在非基本类型或上下转型中,被转换的父类需要检查是否与目的类型相一致,否则,如果在两个完全不相干的类之间进行转换,将会导致编译出错。


const_cast

const_cast<type_id> (expression)
//用于修改类型的const或volatile属性。除了const 或volatile修饰之外,type_id和expression的类型是一样的,一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型,而C不提供消除const的机制。
//常量指针被转化成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

特点:

用于删除 const、volatile 和 __unaligned 特性(如将 const int 类型转换为 int 类型 )


过程中的深拷贝和浅拷贝

  • 去掉对象指针的const,全是原对象
  • 去掉一般对象的const,如果赋值给一般对象则是新对象,否则全是原对象
  • 去掉局部变量的const,全是新对象

dynamic_cast

1. dynamic_cast转换符只能用于指针或者引用。
2. dynamic_cast转换符只能用于含有虚函数的类。
3. dynamic_cast转换操作符在执行类型转换时首先将检查能否成功转换,如果能成功转换则转换之,如果转换失败,如果是指针则返回一个0值,如果是转换的是引用,则抛出一个bad_cast异常。


特点:

• 用于多态类型的转换
• 执行行运行时类型检查
• 只适用于指针或引用
• 对不明确的指针的转换将失败(返回 nullptr),但不引发异常.
• 可以在整个类层次结构中移动指针,包括向上转换、向下转换.


主要用于执行“安全的向下转型”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。
它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。
当用于多态类型时(包含虚函数),它允许任意的隐式类型转换以及相反过程。
向下转化时,如果是非法的_对于指针返回NULL,对于引用抛异常_。要深入了解内部转换的原理。
• 向上转换:指的是子类向基类的转换
• 向下转换:指的是基类向子类的转换
它通过判断在执行到该语句的时候变量的运行时类型和要转换的类型是否相同来判断是否能够进行向下转换。
不过,与static_cast不同,在后一种情况里(即隐式转换的相反过程),dynamic_cast根据RTTI信息检查操作是否有效。
即在转换时dynamic_cast会检查转换是否能返回一个被请求的有效的完整对象。
这种检查不是语法上的,而是真实情况的检查。检测在运行时进行,如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL。


einterpret_cast

reinpreter_cast (expression)
//type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。
//这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。reinpreter_cast是特意用于底层的强制转型,导致实现依赖(就是说,不可移植)的结果。

reinterpret_cast是四种强制转换中功能最为强大的(最暴力,最底层,最不安全),它的本质是编译器的指令.

特点:

• 用于位的简单重新解释.
• 滥用 reinterpret_cast 运算符可能很容易带来风险。除非所需转换本身是低级别的,否则应- 使用其他强制转换运算符之一。
• 允许将任何指针转换为任何其他指针类型(如 char*int*One_class* Unrelated_class* 之类的转换,但其本身并不安全)
• 也允许将任何整数类型转换为任何指针类型以及反向转换。
• reinterpret_cast 运算符不能丢掉 const、volatile 或 __unaligned 特性。
• reinterpret_cast 的一个实际用途是在哈希函数中,即,通过让两个不同的值几乎不以相同的索引结尾的方式将值映射到索引。

示例:

#include <iostream> 
int main()
{
  double a = 1.1;
  char * c = reinterpret_cast<char*>(&a);
  double* b = reinterpret_cast<double*>(c);
  printf("%lf",*b);
        return 0;
}

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

综合示例

#include <iostream>
// 基类
class Base {
public:
    virtual void foo() {}
};
// 派生类
class Derived : public Base {
public:
    void bar() {
        std::cout << "Derived::bar called" << std::endl;
    }
};
int main() {
    // static_cast 示例
    // static_cast 主要用于基本数据类型之间的转换,以及类层次结构中基类和派生类之间的指针或引用的转换。
    // static_cast 不提供运行时类型检查。
    float f = 3.14f;
    int i = static_cast<int>(f);  // 将 float 转换为 int
    std::cout << "i = " << i << std::endl;  // 输出:i = 3
    // const_cast 示例
    // const_cast 主要用于修改类型的 const 或 volatile 属性。
    // const_cast 不提供运行时类型检查。
    const int j = 10;
    int* pj = const_cast<int*>(&j);  // 移除 const 属性
    *pj = 20;  // 修改 j 的值
    std::cout << "j = " << j << std::endl;  // 输出:j = 20
    // dynamic_cast 示例
    // dynamic_cast 主要用于类层次结构中基类和派生类之间的指针或引用的转换,特别是向下转型。
    // dynamic_cast 提供运行时类型检查,如果转换不安全,会返回 nullptr。
    Base* base = new Derived();  // base 实际指向一个 Derived 对象
    Derived* derived = dynamic_cast<Derived*>(base);  // 安全的向下转型
    if (derived) {  // 检查转型是否成功
        derived->bar();  // 输出:Derived::bar called
    }
    // reinterpret_cast 示例
    // reinterpret_cast 主要用于任意类型的指针或引用的转换,以及整数和指针之间的转换。
    // reinterpret_cast 不提供运行时类型检查,使用时需要特别小心。
    long l = reinterpret_cast<long>(base);  // 将 Base* 转换为 long
    Base* base2 = reinterpret_cast<Base*>(l);  // 将 long 转换回 Base*
    delete base;
    return 0;
}


目录
相关文章
|
6天前
|
安全 编译器 C++
C++ `noexcept` 关键字的深入解析
`noexcept` 关键字在 C++ 中用于指示函数不会抛出异常,有助于编译器优化和提高程序的可靠性。它可以减少代码大小、提高执行效率,并增强程序的稳定性和可预测性。`noexcept` 还可以影响函数重载和模板特化的决策。使用时需谨慎,确保函数确实不会抛出异常,否则可能导致程序崩溃。通过合理使用 `noexcept`,开发者可以编写出更高效、更可靠的 C++ 代码。
13 0
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
94 5
|
2月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
29 1
|
2月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
42 3
|
2月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
54 3
|
2月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
2月前
|
C++
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
29 0
|
2月前
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
4月前
|
编译器 C语言 C++
【C++关键字】指针空值nullptr(C++11)
【C++关键字】指针空值nullptr(C++11)
|
4月前
|
存储 编译器 C++
【C++关键字】auto的使用(C++11)
【C++关键字】auto的使用(C++11)