欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > C/C++(九)C语言与C++中的类型转换

C/C++(九)C语言与C++中的类型转换

2025/5/22 9:42:00 来源:https://blog.csdn.net/m0_73682725/article/details/143336301  浏览:    关键词:C/C++(九)C语言与C++中的类型转换

目录

一、C语言中的类型转换

1、隐式类型转换

2、显式类型转换

3、示例代码与缺陷

二、C++中的类型转换

1、static_cast

2、reinterpret_cast

3、const_cast

​编辑

4、dynamic_cast

 三、小总结


C语言的类型转换可读性较差,难以区分;C++为了增强程序的可读性,在兼容C语言类型转换的基础上,又增加了独属于C++的四种类型转换。

本章会从C语言类型转换到C++类型转换,逐一进行介绍。

一、C语言中的类型转换

在C语言里,当赋值运算符左右两侧类型不同 / 函数形参与实参类型不匹配 / 函数返回值类型与接受返回值的类型不一致时,就会发生类型转换。

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

1、隐式类型转换

编译器在编译阶段自己进行的类型转换,通常是意义相近 / 相关的类型之间,可以进行类型转换,能转就转,转不了就会编译失败。

缺陷有些情况下可能会出现一些问题,比如数据精度丢失。

2、显式类型转换

需要用户自己来处理的转换。

缺陷:代码可读性较差,所有的显式转换都是以同一种形式书写,这让我们跟踪错误转换变得困难。

3、示例代码与缺陷

void Test ()
{int i = 1;double d = i;               // 隐式类型转换,数据精度丢失printf("%d, %.2f\n" , i, d);int* p = &i;int address = (int) p;     // 显式的强制类型转换printf("%x, %d\n" , p, address);
}

二、C++中的类型转换

C++标准为了增强程序可读性,引入了四种命名的强制类型转换操作符

static_cast,reinterpret_cast、const_cast、dynamic_cast 

1、static_cast

static_cast 主要用于非多态类型的转换(编译时就进行了转换,所以是静态转换)

编译器中任何的隐式类型转换都可以用 static_cast,代码可读性更高。一般用于意义相近的类型的转换;不能用于两个不相关类型之间的转换。

#include <iostream>
using namespace std;int main()
{double d = 20.15;int a = static_cast<int>(d);cout << a << endl;return 0;
}

2、reinterpret_cast

reinterpret_cast 一般用于对有一定的关联但意义不相近的类型之间进行转换,可以将整形转换为指针,也可以把指针转换为数组;可以在指针和引用之间进行肆无忌惮的转换。

(使用的时候一定要慎之又慎,因为其实际上是从底层对数据进行了重新解释,对平台有很强依赖性,可移植性很差;而且如果类型之间差距过大,还可能造成数据损坏和未定义行为!)

#include <iostream>
#include <cstdint>int main() {// 示例 1: 将整型转换为指针int value = 42;void* ptr = reinterpret_cast<void*>(value);std::cout << "Pointer from integer: " << ptr << std::endl;// 再次转换回整型int original_value = reinterpret_cast<intptr_t>(ptr);std::cout << "Integer from pointer: " << original_value << std::endl;// 示例 2: 将指针转换为整型int* int_ptr = new int(123);uintptr_t address = reinterpret_cast<uintptr_t>(int_ptr);std::cout << "Address as integer: " << address << std::endl;// 再次转换回指针int* original_int_ptr = reinterpret_cast<int*>(address);std::cout << "Value at address: " << *original_int_ptr << std::endl;delete int_ptr;// 示例 3: 在不同类型的指针之间转换class A {};class B {};A* a = new A();B* b = reinterpret_cast<B*>(a);// 注意:这里的转换没有任何实际意义,除非你知道这两个类有某种特殊的关联std::cout << "Pointer to A: " << a << std::endl;std::cout << "Pointer to B (cast from A): " << b << std::endl;delete a;// 示例 4: 在指针和引用之间转换int ref_value = 789;int& ref = ref_value;// 将引用转换为指针int* ref_ptr = &ref;std::cout << "Pointer from reference: " << ref_ptr << std::endl;// 将指针转换为引用int& ref_from_ptr = *reinterpret_cast<int*>(ref_ptr);std::cout << "Reference from pointer: " << ref_from_ptr << std::endl;return 0;
}

3、const_cast

const_cast 最常用的用途是去除 / 增加一个常变量的 const 常量属性,也是四大类型转换中唯一的一个可以操作常变量的转换。参数必须是常变量的指针 / 引用。

#include <iostream>
using namespace std;int main()
{const int num = 2014;int& p = const_cast<int&>(num);cout << num << " " << p << endl;p = 2015;cout << num << " " << p << endl;return 0;
}

 

观察运行结果我们会有个疑问,p 不是 num 的别名吗,为什么 P 改变了,并没有改变 num呢?

这是因为,const_cast 也是个静态转换,在编译期间,编译器会对 const 类型的常变量进行优化,会把 const 常变量直接放入寄存器甚至直接以常量替换,取常变量的值不会从内存里面取,因此 p 在内存中的更改并不会导致寄存器中 num 的取值变化。所以严格意义上说,对常变量的更改也算是一种未定义行为,要尽量避免。 

(PS:如果想让结果正确,可以在 const 前面加上 volatile 关键字,这个关键字会指示编译器不要优化 const ,这样每次取值就直接从内存中取了,结果也就正确了)

#include <iostream>
using namespace std;int main()
{volatile const int num = 2014;int& p = const_cast<int&>(num);cout << num << " " << p << endl;p = 2015;cout << num << " " << p << endl;return 0;
}

4、dynamic_cast

dyanmic_cast是一个动态转换,就是在运行时才进行转换,一般用于向下转换,即把父类的指针 / 引用转换成子类的指针 / 引用。

向上转换:子类对象的指针 / 引用 -> 父类对象的指针 / 引用(不需要强转,赋值兼容原则即可)

向下转换:父类对象的指针 / 引用 -> 子类对象的指针 / 引用(利用 dynamic_cast)

一些注意事项:

1、dynamic_cast 的父类必须含有虚函数,即只能用于多态类型的转换。

2、父类对象无论如何都转换成子类对象,但是父类的指针 / 引用可以通过 dynamic_cast 安全转换为子类的指针 / 引用。(static_cast / 直接转换都是不安全的,子类会比父类多出一块空间,如果转换后的父类指针 / 引用访问了这块不存在的空间,会造成越界;而dynamic_cast会先检查转换是否合法,合法才转换,不合法会直接返回)

#include <iostream>
using namespace std;class A
{
public:virtual void test(){printf("我是A\n");}
};class B : public A
{
public:virtual void test(){printf("我是B\n");}
};void Test(A* pa)
{// 使用 static_cast 进行转换B* pb1 = static_cast<B*>(pa);  // static_cast 不会检查是否越界,可能会转换失败if (pb1){pb1->test();  // 如果 pa 实际上不是 B 的实例,这可能会导致未定义行为}else {cout << "static_cast 转换失败" << endl;}// 使用 dynamic_cast 进行转换B* pb2 = dynamic_cast<B*>(pa);  // dynamic_cast 会检查if (pb2){pb2->test();  // 如果转换成功,调用 B 的 test 方法}else {cout << "dynamic_cast 转换失败" << endl;}
}int main()
{A* a = new A();A* b = new B();cout << "测试 A 类型的对象:" << endl;Test(a);  // pa 实际上是 A 类型的对象cout << "测试 B 类型的对象:" << endl;Test(b);  // pa 实际上是 B 类型的对象delete a;delete b;return 0;
}

  1. 测试 A 类型的对象

    • static_cast 成功将 A* 转换为 B*,但调用 test 方法时,由于 pa 实际上是 A 类型的对象,所以输出 我是A

    • dynamic_cast 失败,因为 pa 实际上不是 B 类型的对象,所以输出 dynamic_cast 转换失败

  2. 测试 B 类型的对象

    • static_cast 成功将 B* 转换为 B*,调用 test 方法时,输出 我是B

    • dynamic_cast 也成功,因为 pa 实际上是 B 类型的对象,所以输出 我是B

 三、小总结

强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是

否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用

域,以减少发生错误的机会。强烈建议:避免使用强制类型转换。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词