C++:类型转换

目录

一. C语言的类型转换

二. C++类型转换

2.1 static_cast

2.2 reinterpret_cast

2.3 const_cast

2.4 dynamic_cast

三. 运行时类型识别 -- RTTI

四. 总结


一. C语言的类型转换

C语言的类型转换分为隐式类型转换和强制类型转换,隐式类型转换发生在相近的类型之间,强制类型转换可以完成不相关类型之间的转换。

  • 隐式类型转换:当运算符两侧的数据类型不同时,其中一个数据的类型会被隐式转换为另一个数据的类型,转换规则遵循图1.1中自上而下的顺序。
  • 强制类型转换:实现不相关类型之间的转换,如:将int型数据转换为int*类型的数据。编译器不会自动进行强制类型转换,需要用户显示的去进行转换。注意:并不是任何不相关的数据都能进行强制类型转换,如自定义类型和内置类型之间不能强转。
图1.1 隐式类型转换顺序

C语言的类型转换有以下缺陷:

  1. 隐式类型转换,有可能造成精度的丢失。
  2. 将所有强制类型转换混在一起,不易区分。 

为了弥补C语言类型转换的缺陷,C++提出了属于自己的四种类型转换方式,但是C++兼容C语言,C语言的类型转换规则在C++中依旧适用。

二. C++类型转换

C++有static_cast、interpret_cast、const_cast、_dynamic四种类型转换方式。

2.1 static_cast

用法:static_cast<转换后的类型>(被转换类型的变量)

功能:用于执行任何C语言中的隐式类型转换,不可以用于非相关类型的强制类型转换。

int main()
{
	double d1 = 12.1234;
	int i1 = static_cast<int>(d1);  //将d1的类型转换为int

	int i2 = 3;
	double d2 = static_cast<double>(i2);  //将i2的类型

	int a = 1234567;
	//int* pa = static_cast<int*>(a);   //无法实现不相关类型之间的强制类型转换

	return 0;
}

2.2 reinterpret_cast

用法:reinterpret_cast<转换后的类型>(被转换类型的变量)

功能:指向不相关类型之前的强制类型转换,不可用于相关类型之间的隐式类型转换

注意:如果被转换类型的对象具有const属性,那么使用reinterpret_cast不能取消其const属性,如:const int b = 10; int* pb = reinterpret_cast<int*>(&b)就无法通过编译,因为&b本身的类型为const int*, reinterpret_cast<int*>(&b)将其const属性取消了。

但是,使用C语言的强制类型转换(int*)&b能够取消const属性。

int main()
{
	int a = 1234567;
	int* pa = reinterpret_cast<int*>(a);
	std::cout << pa << std::endl;

	double d = 10.11;
	//int i = reinterpret_cast<int>(d);  //不能进行相近类型之间的转换

	const int b = 10;
	//int* pb1 = reinterpret_cast<int*>(&b);  //不能取消&b的const属性
	int* pb2 = (int*)&b;   //编译通过
	*pb2 = 20;

	return 0;
}

2.3 const_cast

用法:const_cast<不具有const属性的类型>(具有const属性的对象)

功能:取消原本对象/变量类型的const属性

如:const int a = 10,不能直接对a的值进行修改,但是,如果通过const_cast操作符,拿到不具有const属性的a的地址,就可以通过解引用改变a的值。

使用reinterpret_cast无法取消const属性。

int main()
{
	const int a = 1;
	int* pa = const_cast<int*>(&a);
	*pa = 2;
	return 0;
}

2.4 dynamic_cast

用法:dynamic_cast<子类指针或引用类型>(父类指针或引用)

功能:在保证安全的前提下,将父类的指针或引用类型转换为子类的指针或引用类型

  • 正常情况下,派生类对象可以赋值给基类对象,基类的对象一定不能赋值给派生类的对象。派生类的指针或引用可以赋值给基类的指针或引用。
  • 基类的指针或引用经过强制类型转换后,可以赋值给派生类的指针或引用,但这样并不安全,容易出现越界访问的问题。
  • dynamic_cast可以用于将基类对象的引用或指针,经强制类型转换后赋值给派生类的引用或指针。使用dynamic_cast要么类型转换失败,如果成功就一定安全。

关于dynamic_cast强制类型转换,有以下两点注意事项:

  1. 要求基类必须有虚函数,否则无法通过dynamic_cast实现类型转换。
  2. 如果强制将基类的引用转换为派生类的引用时失败,dynamic_cast会抛出异常,如果强制将基类的指针转换为派生类的指针时失败,dynamic_cast返回空指针nullptr。

一般来说,如果某个基类的引用或指针,实际指向某个派生类对象,dynamic_cast就会强转成功,如果基类的引用或指针就是指向某个基类对象而不是派生类对象,强转类型转换就会失败。

如下面的代码,定义了两个基类指针pa1和pa2,pa1实际指向基类对象a,pa2实际指向派生类对象b,将pa1和pa2分别作为参数传给func函数,func函数中尝试尝试使用dynamic_cast将它们强转类型转换为派生类指针,pa1转换失败,pa2转换成功。

class A
{
public:
	virtual void func() { }

public:
	int _a1 = 10;
};

class B : public A
{
public:
	int _b1 = 20;
};

void func(A* pa)
{
	//如果转换成功pb为正确的派生类对象地址
	//如果转换失败pb为nullptr
	B* pb = dynamic_cast<B*>(pa);

	//如果转换成功
	if (pb)
	{
		std::cout << "转换成功" << std::endl;
		std::cout << "_a1 = " << pb->_a1 << std::endl;
		std::cout << "_b1 = " << pb->_b1 << std::endl << std::endl;
	}
	else   //如果转换失败
	{
		std::cout << "转换失败" << std::endl;
		std::cout << "_a1 = " << pa->_a1 << std::endl << std::endl;
	}
}

int main()
{
	A a;
	B b;

	A* pa1 = &a;
	A* pa2 = &b;

	func(pa1);  //转换失败
	func(pa2);  //转换成功

	return 0;
}
图2.1 代码运行结果

三. 运行时类型识别 -- RTTI

C++通过以下三种方式,进行运行时类型失败:

  1. typeid -- 以字符串的形式获取变量/对象的类型
  2. dynamic_cast运算符 -- 检验基类的指针或引用能否转换为派生类的指针或引用。
  3. decltype关键字 -- 自动识别变量类型,可用其返回结果定义新的变量的类型。

四. 总结

  • C语言支持隐式类型转换和强制类型转换,隐式类型转换发生在相近类型之间,强制类型转换用于不相关类型之间的转换。
  • C++支持四种方式的类型转换,static_cast执行相近类型见的转换、reinterpret_cast用于不相关类型的强制转换,但不能取消const属性、const_cast用于取消对象类型的const属性、dynamic_cast用于将基类的指针或引用转换为派生类的指针或引用,dynamic_cast要求基类要有虚函数,否则会编译报错,dynamic_cast执行强制类型转换要么编译报错,如果转换成功就一定能保证安全。
  • C++通过typeid、dynamic_cast和decltype三种方式实现运行时类型识别。
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值