c++ reinterpret_cast类型转换规律总结

1.概要

c++提供如下几种转换,具体如下。

  • static_cast:用于非多态类型的转换。
  • dynamic_cast:用于多态类型的转换,主要用于向下类型转换(从基类指向派生类的指针/引用),会检查转换的有效性,如果转换不安全,则无法进行转换。
  • const_cast:用于去除const或volatile属性。
  • reinterpret_cat:允许所有指针转换为其他指针类型。并允许任何整型转换为任何指针类型反之亦然。

我这里只针对reinterpret_cat的转换进行实验,因为前三种用起来很简单,也很明确,似乎都没有什么明显的价值,哈哈。
实验结果如下:
基本的结论就是,reinterpret_cat转换就是你如果想转,我就给你转,对象的赋值就是按照内存的面积赋值,其他的我都不管。至于有什么价值,就根据自己需要的场景使用吧,比如无法用面向对象来多态,那么用这个方法也许能起到一些特殊的效果。

2.代码

#include <iostream>
using namespace std;

//名称和变量的转换有什么差别
namespace test1 {
	class A
	{
	public:
		int a=0;
		void fun() {
			cout << "A fun a:" << a << "\n";
		}
	};
	class B
	{
	public:
		int a=1;
		void fun() {
			cout << "B fun a:" << a << "\n";
		}
	};
	void test() {
		cout << "------------------------------------------\n";
		A* a = new A();
		B* b = reinterpret_cast<B*>(a);
		b->fun();
		/*
		* 执行结果:使用A的变量,使用B的函数
		B fun a:0 
		Hello World!*/
	}
}
//不同的变量能否转换成功:可以匹配
namespace test2 {
	class A
	{
	public:
		int a = 2;
		void fun() {
			cout << "A fun a:" << a << "\n";
		}
	};
	class B
	{
	public:
		int b = 1;
		void fun() {
			cout << "B fun a:" << b << "\n";
		}
	};
	void test() {
		cout << "------------------------------------------\n";
		A* a = new A();
		B* b = reinterpret_cast<B*>(a);
		b->fun();
		/*
		* 执行结果:使用A的变量,使用B的函数
		* 虽然变量名,不同了,因为变量只有一个,且类型相同,那么可以匹配
		* B fun a:2 
		*/
	}
}
//变量类型不同是否匹配:不匹配
namespace test3 {
	class A
	{
	public:
		int a = 2;
		void fun() {
			double d = a;
			cout << "A fun a:" << d << "\n";
		}
	};
	class B
	{
	public:
		double b = 1;
		void fun() {
			cout << "B fun a:" << b << "\n";
		}
	};
	void test() {
		cout << "------------------------------------------\n";
		A* a = new A();
		a->fun();
		B* b = reinterpret_cast<B*>(a);
		b->fun();
		/*
		* 结果:
		* A fun a:2
		* B fun a:-7.84591e+298
		* 变量如果类型不同,就无法匹配,但是结果又不像是B类的b(1)
		* 那么问题的原因有可能是安装内存的区域拷贝数据了A拷贝给B所以造成B.b不是1
		*/
	}
}
namespace test4 {
	class A
	{
	public:
		char a = 1;
		char b = 2;
	};
	class B
	{
	public:
		char b[2] = { 3,4 };
		void fun() {
			for (size_t i = 0; i < 2; i++)
			{
				cout << (int)b[i];
			}
			cout << endl;
		}
	};
	void test() {
		cout << "------------------------------------------\n";
		A* a = new A();
		B b;
		b.fun();
		try
		{
			B* b = reinterpret_cast<B*>(a);
			b->fun();
		}
		catch (const std::exception& e)
		{
			cout << "yichang " << endl;
		}
		/*
		* 结果:
		* 34
		* 12
		* 从结果看,证实了上面的猜测,对象的变量是安装内存拷贝的
		* 那也就是从这个使用得到最终的结果:reinterpret_cast类中转换是安装内存的位置匹配的,和变量的名称类型都没有关系。只有内存的位置匹配,就可以安装这个原则拷贝
		*/
	}
}
//试一试A的内存多与B的情况
namespace test5 {
	class A
	{
	public:
		int a = 1;
		int b = 2;
	};
	class B
	{
	public:
		int a=3;
		void fun() {
			cout <<a<< endl;
		}
	};
	void test() {
		cout << "------------------------------------------\n";
		A* a = new A();
		B b;
		b.fun();
		try
		{
			B* b = reinterpret_cast<B*>(a);
			b->fun();
		}
		catch (const std::exception& e)
		{
			cout << "yichang " << endl;
		}
		/*
		* 结果:
		* 3
		* 1
		* 从结果看,B安装自己需要的内存位置有A的内存中获取
		*/
	}
}
namespace test6 {
	class A
	{
	public:
		int a = 1;
	};
	class B
	{
	public:
		int a = 2;
		int b = 3;
		void fun() {
			cout << a << endl;
			cout << b << endl;
		}
	};
	void test() {
		cout << "------------------------------------------\n";
		A* a = new A();
		B b;
		b.fun();
		try
		{
			B* b = reinterpret_cast<B*>(a);
			b->fun();
		}
		catch (const std::exception& e)
		{
			cout << "yichang " << endl;
		}
		/*
		* 结果:
		* 2
		* 3
		* 1 //由a获取
		* -33686019 //未知的值,不确定是由A获取的,还是默认的初始值。但这部分我认为如果保持B的默认值3应该是更好的
		* 从结果看,B安装自己需要的内存位置有A的内存中获取
		*/
	}
}


int main()
{
	test1::test();
	test2::test();
	test3::test();
	test4::test();
	test5::test();
	test6::test();
    std::cout << "Hello World!\n";
}

3.运行结果

------------------------------------------
B fun a:0
------------------------------------------
B fun a:2
------------------------------------------
A fun a:2
B fun a:-7.84591e+298
------------------------------------------
34
12
------------------------------------------
3
1
------------------------------------------
2
3
1
-33686019

4.关于reinterpret_cast 

1.reinterpret_cast 

reinterpret_cast 是 C++ 中的一个强制类型转换操作符,它允许开发者将一种指针类型转换为另一种不同的指针类型,或者将指针类型转换为整数类型。这种转换是非常底层和危险的,因为它不进行任何验证或保证转换后的类型是否有效或安全。使用 reinterpret_cast 时,开发者需要承担全部责任确保转换的合理性和安全性。

使用场景

  1. 低级别的系统编程:在需要与硬件交互或执行底层系统操作时,可能需要将特定类型的指针转换为设备所需的指针类型。
  2. 与C的互操作:在与用C语言编写的库或API交互时,可能需要按照C库期望的方式转换指针类型。
  3. 特殊优化:在某些情况下,开发者可能通过 reinterpret_cast 实现特定的性能优化,但这通常需要对底层实现有非常深入的理解。

示例

#include <iostream>  
  
int main() {  
    int a = 42;  
    int* pInt = &a;           // 整数指针  
    char* pChar = reinterpret_cast<char*>(pInt);  // 将整数指针转换为字符指针  
  
    std::cout << "Integer value: " << *pInt << std::endl;  
    std::cout << "Char value (reinterpreted): " << static_cast<int>(*pChar) << std::endl;  // 输出该位置的字符的整数值(通常是ASCII码)  
  
    return 0;  
}

注意事项

  • 类型安全性reinterpret_cast 不检查操作是否安全,它仅仅重新解释了内存中的位模式。这可能导致未定义行为,比如访问无效内存。
  • 可移植性问题:使用 reinterpret_cast 的代码可能在不同平台或编译器上行为不一致,因为它依赖于具体的内存布局和对象表示。
  • 避免滥用:应尽可能避免使用 reinterpret_cast,除非确实需要并且完全理解其潜在风险。

与其他转换操作符比较

  • static_cast:用于编译时已知的类型转换,比如基类和派生类之间的转换,或者基本数据类型之间的转换。
  • dynamic_cast:用于运行时类型识别,确保类型安全,但性能开销较大。
  • const_cast:用于修改类型的const或volatile属性。

总的来说,reinterpret_cast 是一个强大但危险的工具,应该谨慎使用。在大多数情况下,更推荐使用 static_castdynamic_cast 或其他更安全的类型转换方法。

2.reinterpret_cast与其他几种类型转换的对比 

reinterpret_cast 是 C++ 中四种类型转换操作符之一,其他三种分别是 static_castdynamic_cast 和 const_cast。每种转换操作符都有其特定的用途和行为,下面是对它们的对比:

转换操作符主要用途安全性类型检查使用场景
reinterpret_cast用于任意类型之间的转换,特别是指针和整数之间的转换最低不进行低级别的系统编程、与C的互操作、特殊优化
static_cast用于编译时已知的类型转换,如基本类型之间的转换、类层次结构中的向上或向下转换较高编译时基本类型转换、安全的类层次结构转换
dynamic_cast用于运行时类型识别,特别是类层次结构中的向下转换最高运行时确保类型安全的类层次结构转换
const_cast用于去除或添加 const 或 volatile 属性中等编译时修改类型的 const 或 volatile 属性

详细对比

  1. reinterpret_cast

    • 用途reinterpret_cast 可以在任意类型之间进行转换,特别是将指针或引用转换为完全不同的类型,甚至将指针转换为整数或将整数转换为指针。
    • 安全性reinterpret_cast 不进行任何安全检查,只是简单地按位重新解释对象的内存表示。这可能导致未定义行为、数据丢失或程序崩溃。
    • 类型检查:不进行任何类型检查。
    • 使用场景:通常用于低级别的系统编程、与C的互操作或特殊优化,但需要开发者对转换的安全性和后果有深入的理解。
  2. static_cast

    • 用途static_cast 用于编译时已知的类型转换,如基本类型之间的转换、类层次结构中的向上或向下转换(向下转换可能不安全)。
    • 安全性static_cast 会进行一定程度的类型检查,以确保转换在编译时是合理的。但对于向下转换,它不会进行运行时类型检查,因此可能不安全。
    • 类型检查:编译时进行类型检查。
    • 使用场景:适用于大多数基本的、安全的类型转换场景。
  3. dynamic_cast

    • 用途dynamic_cast 主要用于类层次结构中的向下转换,它可以在运行时检查转换的合法性。
    • 安全性dynamic_cast 在运行时进行类型检查,如果转换失败,会返回空指针(对于指针类型)或抛出异常(对于引用类型)。因此,它是类型最安全的转换操作符。
    • 类型检查:运行时进行类型检查。
    • 使用场景:适用于需要确保类型安全的类层次结构转换场景,特别是涉及多态的类。
  4. const_cast

    • 用途const_cast 用于去除或添加 const 或 volatile 属性,以修改对象的底层 const 性。
    • 安全性const_cast 本身不会进行安全检查,只是简单地修改对象的 const 或 volatile 属性。因此,如果滥用它去修改一个原本不应被修改的 const 对象,可能会导致未定义行为。
    • 类型检查:不进行类型检查,只是修改对象的 const 或 volatile 属性。
    • 使用场景:通常用于修改需要通过指针或引用访问的 const 对象的值,但需要开发者确保这种修改是安全的。

总结

每种类型转换操作符都有其特定的用途和适用场景。reinterpret_cast 提供了最大的自由度,但也是最不安全的;static_cast 适用于大多数基本的类型转换场景;dynamic_cast 提供了类型安全的类层次结构转换;const_cast 则用于修改对象的 const 或 volatile 属性。在使用这些转换操作符时,开发者需要根据具体情况谨慎选择,并确保转换的安全性和合理性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值