C++ --- 类型转换(static_cast、reinterpret_cast、const_cast、dynamic_cast)以及其适用环境

文章介绍了C语言中的隐式类型转化和C++中的四种强制类型转化操作符:static_cast用于非多态类型的安全转化,reinterpret_cast处理位模式的重新解释,const_cast用于移除const属性,dynamic_cast则在多态类型间进行安全的向下转化。此外,还提到了explicit关键字防止隐式类型转换。

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


前言

你知道C中的类型转化,那么C++的呢??


1、C语言中的类型转换

首先,C语言中的内置类型之间是存在等级的;
如下等级依次递减;
(1)long double

(2)double

(3)float

(4)unsigned long long

(5)long long

(6)unsigned int

(7)int
1.而高等级类型的变量给低等级变量的复制,之间存在隐式类型转化
例如下:

int a=10;
double b= 20;
a=b;

两类型不同的变量复制,编译器首先会进行隐式类型转化,而高等级的double类型向int类型转化是可以的!!!反之若不行,则会报错;

2.而关于两个类型不同指针之间进行赋值,则通常发生强制类型转化
例如:

double b=20;
int * p=&b;

补充关于指针的一个基本概念:

  • 指针实则就是一个地址;
  • 在32位系统下,任意类型指针的大小均为4字节,那么不同类型体现在什么地方呢???
    不同类型体现在对该指针解引用时(即访问这个指针指向空间的内容时),从这个地址向后访问多少个字节;)

此情况就会报错,在于&b的类型为double*,也就意味着岂会从起始地址向后访问8个字节,而int*,则只会向后访问4个字节;所以其是无法进行隐式类型转换的,而是需要强转
改写为: int* p=(int*) &b;
其会将double* 型的变量当作 int* 类型进行处理;
(强制类型转化一般是会生成中间变量的!!!而此情况不会)

缺陷: 首先转化的可视性比较差,所有的转型形式都是以一种相同形式书写,难以追踪错误;

2、C++中的类型转化

而C++中引入了四种的强制类型转型操作符,static_cast、reinterpret_cast、const_cast、dynamic_cast
而之所以需要四种类型转化,一方面在于:

  • 部分隐式类型转换存在,存在精度的缺失,例如double类型给int类型赋值,实则是将double类型变量的int部分赋值给int类型变量,自然小数部分则会丢失;
  • 再者强转类型转换所以情况易混合一起,代码不够清晰;

接下来,就为大家介绍C++引入的这四种强制类型转换操作符;

2.1、static_cast

  • static_cast用于非多态类型的转换(静态转化),同时其也是支持隐式类型的转化,但不能用于两个无关类型的相互转化;
  • 而对一个类来说的非多态类型可以简单的理解为,该类对象调用成员函数,无论是普通成员函数,还是虚函数,其调用都是本类的成员函数;
double b=20.123;
int a=b;//C中的隐式类型转化
int c=static_cast<int> (b);//支持

注:static_cast可用于继承体系下类层次之间的转化,向上转型是安全的(赋值兼容规则),但是向下转型是不安全的(因为其可能会访问基类不存在的成员)

2.2、reinterpret_cast

reinterpret_cast支持将一种类型转换为另外一种不同类型,其通常为操作数的位模式提供给较低层次的重新解释;

double b=10.123;
//C中的强制类型转换
int *p=(int*)&b;
//reinterpret_cast是支持强制类型转化的
//但是针对const T*类型的转化,reinterpret_cast是不支持的,而强转则可以达到~~
int* p_=reinterpret_cast<int*> (&b);

关于函数指针:

##FUNC是对一个参数为空返回值为void的函数的指针重命名
typedef void (*FUNC)();
int DoSomething(int i)
{
	cout << "DoSomething::" <<i<< endl;
	return 0;
}
void Test()
{
	##仍能通过编译,且运行之后i打印了为一个随机数
	FUNC f = reinterpret_cast<FUNC>(DoSomething);
	f();
}

首先以上的代码是不可移植的,其次C++并保证所有函数指针都能一样的使用,即可能产生不确定的结果;

2.3、const_cast

const_cast最常用的用途就是删除变量的const属性;

const int a=10;
//C中强制类型转化
int* b=(int*) &a;
//C++ const_cast
int b_=const_cast<int*> (&a);

而关于const_cast的使用,其目的并不是为了让你去修改一个本身被定义为const的值,因为这样的结果是无法预期的,const_cast的目的在于修改一些指针/引用的权限, 如果我们原来无法通过这些指针/引用修改某块内存的值,那么现在就可以了!!
如下代码:

const int a=30;
const int* pa=&a;
int* b=const_cast<int*> (pa);
*b=66;

2.4、dynamic_cast

dynamic_cast主要用于将父类指针(引用)转化为子类指针(引用);

向上转型:子类的指针或引用指向父类的指针或引用;(不需要转化,符合赋值兼容规则)
向下转型:父类的指针或引用指向子类的指针或引用; (采用dynamic_cast是安全的)

首先dynamic_cast适用于继承的体系当中,且其只能用于含有虚函数的类中!!!

那么你知道为什么要有虚函数吗????

  • 首先dynamic_cast,是在运行时进行转换,而运行时转换就需要只知道类对象的信息(继承关系等);
  • 而其运行时在虚函数表中获取类对象信息;
    • 有了虚函数,就会修改构造函数,类对象前四个字节,这个指针便指向该类对象的所有虚函数,包括父类;
    • 派生类会继承基类的虚函数表,所以通过这个虚函数表,确定该类对象的父类,在转换时即可判断对象有无继承关系~~

而关于其返回值,dynamic_cast会先检查是否能转化成功,成功返回其对象地址,反之则返回0;

例如,如下代码:
一个Animal基类,有两个类,Dog类,Cat类,继承于Aniaml类;

class Animal
{
public:
	void call()
	{
		cout << "吼叫" << endl;
	}
};

class Cat : public Animal 
{
public:
	void call()
	{
		cout << "喵喵" << endl;
	}
};

class Dog :public Animal
{
public:
	void call()
	{
		cout << "汪汪" << endl;
	}
};

如下函数:

void textAniamlCall_1(Animal* an)
{
	//C中的强转可以实现~
	Dog* dog = (Dog*)an;
	dog->call();
	//当时函数传参假如是一个Dog对象,此时在强转为Cat对象,其实是一种错误的操作~
	Cat* cat = (Cat*)an;
	cat->call();
}

此时便可使用dynamic_cast进行类型转化
前提是将Animal类中的Call函数修改为虚函数~~

void textAniamlCall_1(Animal* an)
{	
	Dog* dog = dynamic_cast<Dog*>(an);
	if(dog)
	dog->call();

	Cat* cat = dynamic_cast<Cat*>(an);
	if(cat)
	cat->call();
}

此时就能满足,无论传参Dog类对象还是Cat类对象,在dynamic_cast作用下,都可使用对应的类中的成员函数;

注意:
1.强制类型转化的本身是关闭或挂起了正常的类型检测的,所以能不用强制类型转化就不要用强制类型转化;
2.而当非强制类型转化时,应限制强制类型转化值的作用域,以减少发送错误的可能,并且强烈不建议是用强制类型转化;

2.5、explicit

explicit是避免了像单参构造函数,导致的类型转化
如下代码

class A
{
public:
	A(int num):
		aa(num)
	{
	}

	int aa;
};

void textA()
{
	//编译不会报错
	//其实是通过10,调用对应A(int)这一单参构造函数创建了一个对象,赋值给a;
	A a = 10;
}

但是在加exlicit关键字后,在VS下出现了如下报错
在这里插入图片描述

总结

以上便是博主总结的C/C++中的类型转化;

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值