一文带你探索C++中类型转换的奥秘

 更新时间:2023年10月25日 14:02:54   作者:大神仙  
C++ 提供了四种类型转换方式,帮助我们在不同数据类型之间进行有效的数据传递和操作,这些类型转换方式在不同的场景下有各自的优势和适用性,下面我们就来深入了解一下吧

const_cast(常量转换)

const_cast(常量转换)是一种类型转换运算符,用于修改类型的const或volatile属性。它通常用于将const变量转换为非常量类型,或者将volatile变量转换为非volatile类型。用法如下:

const_cast<new_type>(expression)

new_type是你要转换成的类型,expression是要被转换的表达式。

示例

int main() {

    const int a = 10;

    //    int* pA = &a;//编译错误,不能将一个非常量指针指向一个常量对象。
    int* pA = const_cast<int*>(&a);
    *pA = 20;

    //输入10 20
    cout << "a:" << a << " *pA:" << *pA  << endl;
}

上面的代码定义一个 const int 类型的变量 a,我们想要将其转换为 int 类型。直接用一个指针pA指向这个a时,由于a本身是const类型,会导致编译错误。所以我们可以用 const_cast 把它做一个类型转换,去除 a 的 const 修饰符。然后修改 *pA 的值。

但是大家需要注意,最后的打印输出是a:10 *pA:20

即使你使用 const_cast 去除了指向 a的指针的常量性, *pA = 20 修改了*pA 的值,实际上并不会影响 a 的输出,这是 C++ 语言的常量性规则所决定的。因为它是一个常量。在编译时,编译器将 a 的值直接插入到代码中,而不是通过指针 pA 访问 a。因此无论如何修改 *pAa的值都保持不变。

const_cast 在某些情况下可以提高代码的可读性和减少冗余代码,但也存在一些缺点,例如增加代码的复杂度和容易产生歧义。

reinterpret_cast(重新解释转换)

reinterpret_cast是一种非常危险类型转换。它不会检查我们所指向的内容,也不会检查我们这个类型的本身。它只是做了一个重新的解释,我们要在转换的过程当中,保证它转换前和转换后占用的内存大小应该是一致的。用于在不同类型的指针之间进行转换,用法如下:

reinterpret_cast<new_type>(expression)

示例

int Test() {
    std::cout << "Test function called." << std::endl;
    return 0;
}

int main() {

    //创建一个 FuncPtr 的函数指针类型。指向没有参数和返回值的函数。
    typedef void(*FuncPtr) ();
    FuncPtr funcPtr;

    //    funcPtr = &Test;

    funcPtr = reinterpret_cast<FuncPtr>(&Test);
    funcPtr();


    return 0;
}

上述代码 Test 函数的返回类型是 int,而 FuncPtr 类型是 void(*)(),这两者的返回类型不匹配,因此不能将 Test 函数指针直接赋给 funcPtr。可以通过reinterpret_cast 显式类型转换来解决这个问题,funcPtr = reinterpret_cast<FuncPtr>(&Test)Test 函数的指针转换为 FuncPtr 类型的函数指针。

reinterpret_cast不进行类型检查非常灵活,可以在不同指针类型之间进行转换,包括将指针从对象类型转换为其他类型,或者在整数类型和指针之间进行转换。但是reinterpret_cast是非常危险的。因为他把这个检查的大部分工作交给程序员自身来管理的,可能导致转换不合理或不安全。

static_cast(静态转换)

static_cast(静态转换)可用于对基本类型进行转换,例如int *double *,有继承关系的类对象和类指针之间转换。要注意的是,如果用static_cast做一个继承关系的转换,安全问题需要由程序员自身来保障。

比如说动物,它有一个类叫鸭子,那么鸭子它一定是一种动物,所以它有动物的行为。但是动物未必都有鸭子的行为,所以如果我们把鸭子转换成动物,就是一个叫向上转换的过程。如果向下转换,那就是把动物转换成鸭子。但并不是所有的动物都是鸭子,所以这个地方就存在一些潜在的危险。如果我们使用static_cast就不会发现这样的问题。但如果我们使用dynamic_cast,就会帮我们检查出来这种错误。

示例

class Base
{
public:
    Base() : _i(0) {}
    virtual void T() { cout << "Base:T" << _i << endl; }
private:
        int _i;
};
class Derived : public Base {
public:
    Derived() : _j(1) {}
    virtual void T() { cout << "Derived:T" << _j << endl; }
private:
    int _j;
};

void main() {
    int intValue = 5;
    double intValue2 = static_cast<double>(intValue);
    cout << intValue << " " << intValue2  << endl;//5 5                  

    double dValue = 5.6;
    int dValue2 = static_cast<int>(dValue);
    cout << dValue << " " << dValue2  << endl;//5.6 5  丢失精度

    Base base;
    Derived derived;

    Base* pBase;
    Derived* pDerived;
	// 父类--》子类  static_cast未做检查 可能导致运行时错误
    pDerived = static_cast<Derived*>(&base);
    if (pDerived == NULL) {
        cout << "unsafe static cast from Base to Derived" << pDerived << endl;
    }
}

上面的static_cast将base转化为Derived*,可能导致运行时错误。所以在进行类型转换时,要注意类型匹配规则。确保转换是安全的并且符合预期。例如,在进行向下转型时,需要确保子类对象可以存储父类对象。

dynamic_cast (动态转换)

dynamic_cast (动态转换)用于在类的继承层次之间进行类型转换,它既允许向上转型,也允许向下转型。向下转型会进行检测,如果转换失败则返回空指针或抛出std::bad_cast异常。用法如下:

dynamic_cast<new_type>(expression)

new_type 和 expression 必须同时是指针类型或者引用类型。

示例

class Base
{
public:
    Base() : _i(0) {}
    virtual void T() { cout << "Base:T" << _i << endl; }
private:
        int _i;
};
class Derived : public Base {
public:
    Derived() : _j(1) {}
    virtual void T() { cout << "Derived:T" << _j << endl; }
private:
    int _j;
};

void main() {

    Base base;
    Derived derived;

    Base* pBase;
    Derived* pDerived;
    
	// 父类--》子类  pDerived输出NULL
    pDerived = dynamic_cast<Derived*>(&base);
    if (pDerived == NULL) {
        cout << "unsafe dynamic cast from Base to Derived" << endl;
    }
}

上述代码创建了一个基类 Base 和一个派生类 Derived,然后通过dynamic_cast,将基类指针Base转换为派生类指针 pDerived。,dynamic_cast 返回 NULL 表示转换失败。

在动态类型转换中,只能将一个指向派生类对象的指针转换为基类指针,而不是反过来。这是因为派生类对象包含了基类的部分,但反之并不成立。

如果想安全地将指向基类对象的指针转换为指向派生类对象的指针,要确保对象实际上是派生类对象。

总结

const_cast

用于转换指针或引用,去掉类型的const属性;

reinterpret_cast

重新解释类型,既不检查指向的内容,也不检查指针类型本身;但要求转换前后的类型所占用内存大小一致,否则将引发编译时错误。

static_cast

用于基本类型转换,有继承关系类对象和类指针之间转换,由程序员来确保转换是安全的,它不会产生动态转换的类型安全检查的开销;

dynamic_cast

只能用于含有虚函数的类,必须用在多态体系中,用于类层次间的向上和向下转化;向下转化时,如果是非法的对于指针返回NULL;

到此这篇关于一文带你探索C++中类型转换的奥秘的文章就介绍到这了,更多相关C++类型转换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言 递归解决青蛙跳台阶问题

    C语言 递归解决青蛙跳台阶问题

    递归做为一种算法在程序设计语言中广泛应用。基本含义&#8203;是指函数/过程/子程序在运行过程序中直接或间接调用自身而产生的重入现象。在计算机编程里,递归指的是一个过程:函数不断引用自身,直到引用的对象已知
    2021-11-11
  • C语言实现打砖块游戏

    C语言实现打砖块游戏

    这篇文章主要为大家详细介绍了C语言实现打砖块游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • Matlab利用随机森林(RF)算法实现回归预测详解

    Matlab利用随机森林(RF)算法实现回归预测详解

    这篇文章主要为大家详细介绍了Matlab如何利用随机森林(RF)算法实现回归预测,以及自变量重要性排序的操作,感兴趣的小伙伴可以了解一下
    2023-02-02
  • C++之类的静态变量

    C++之类的静态变量

    这篇文章主要介绍了C++之类的静态变量的相关资料,需要的朋友可以参考下
    2015-06-06
  • VC++进度条process Bar的用法实例

    VC++进度条process Bar的用法实例

    这篇文章主要介绍了VC++进度条process Bar的用法,是进行VC++应用程序开发中非常常见的实用技巧,需要的朋友可以参考下
    2014-10-10
  • C++如何实现简易扫雷游戏

    C++如何实现简易扫雷游戏

    这篇文章主要为大家详细介绍了C++如何实现简易扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • 详解c++种gmock单元测试框架

    详解c++种gmock单元测试框架

    这篇文章我们给大家分享了关于c++种gmock单元测试框架的相关知识点内容,有兴趣的朋友们学习下。
    2018-08-08
  • C++使用模板实现单链表(类外实现)

    C++使用模板实现单链表(类外实现)

    这篇文章主要为大家详细介绍了C++使用模板实现单链表的相关资料,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • C++循环链表之约瑟夫环的实现方法

    C++循环链表之约瑟夫环的实现方法

    这篇文章主要介绍了C++循环链表之约瑟夫环的实现方法,对于学习数据结构与算法有一定的借鉴价值,需要的朋友可以参考下
    2014-09-09
  • C语言 详细讲解接续符和转义符的使用

    C语言 详细讲解接续符和转义符的使用

    接续符是用来告诉编译器行为的符号,那编译器遇到接续符是什么行为呢,就是去掉接续符,然后把下一行连接到现在这行上面,转义符是主要用于表示无回显字符,也用于表示常规字符,转义符必须放在单引号或者双引号里面
    2022-04-04

最新评论