C++的类型转换

文章目录

  • 一. C语言的类型转换
  • 二. C++的四种类型转换
    • 1. static_cast
    • 2. reinterpret_cast
    • 3. const_cast
    • 4. dynamic_cast
  • 三. RTTI
  • 结束语

一. C语言的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就会发生类型转化
C语言总共有两种形式的类型转换:隐式类型转换显示类型转换(强制类型转化)

  1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
  2. 显示类型转化:需要用户自己指定
void Test ()
{
     int i = 1;
     // 隐式类型转换
     double d = i;
     
     int* p = &i;
     // 显示的强制类型转换
     int address = (int) p;
}

缺陷:
转换的可视性比较差,所有的转换形式都是相同形式书写,难以跟踪错误的转换

二. C++的四种类型转换

C语言风格的转换格式很简单,但是也有缺点:

  1. 隐式类型转化可能出现精度丢失,截断等问题
  2. 显示类型转换将所有情况混合在一起,代码不够清晰

因此C++提出了自己的类型转换风格,引入了四种命名的强制类型转换操作符
static_castreinterpret_castconst_castdynamic_cast

1. static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,即可用于意义相近的类型转换

void test1()
{
	double a = 12.34;
	//都是表述数值
	int b = static_cast<int>(a);
	cout << b << endl;
}

2. reinterpret_cast

reinterpret(重新解释),该操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型

void test2()
{
	double a = 12.34;
	//都是表述数值
	int b = static_cast<int>(a);
	//数值转换成地址
	int*p = reinterpret_cast<int*>(b);
}

3. const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值

void test3()
{
	const int a = 2;
	//删除const属性
	int *p = const_cast<int*>(&a);
	*p = 3;
	cout << *p << endl;
}

在这里插入图片描述

4. dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针/引用(动态转换)

向上转型:子类指针/引用–>父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类指针/引用–>子类指针/引用(用dynamic_cast转是安全的)

注意:

  1. dynamic_cast 只能用于父类含有虚函数的类
  2. dynamic_cast会先检查是否转换成功,能成功则转换,不能则返回0

为什么说向下转型用dynamic_cast是安全的,强制转换为什么不安全?

比如这样一个继承体系

class A
{
public:
	virtual void fun()
	{}
private:
	int _x;
};

class B :public A
{
private:
	int _y;
	int _z;
};

B继承A,但B拥有自己的成员变量,如果强制类型转换,情况如下:

C++的类型转换_第1张图片

因为B比A大,所以B的指针能访问的空间更多,但是这部分并不属于A。如果原先是指向A类型对象的指针,那么强转成B类型的指针,访问权限变大,但那部分并不属于A类型对象,这就会造成越界

强制类型转换并不会管原先指向的到底是父类对象还是子类对象,都会转换成功。
而dynamic_cast会检查,如果是原先是父类对象,则转换失败返回0,如果是子类对象,则转换成功。

void fun(A* pa,const string&str)
{
	// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
	cout << str << "转换" << endl;
	B* pb1 = (B*)(pa);
	B* pb2 = dynamic_cast<B*>(pa);
	cout << "pb1:" << pb1 << endl;
	cout << "pb2:" << pb2 << endl << endl;
}

void test4()
{
	A a;
	B b;
	fun(&a,"父类对象");
	fun(&b,"子类对象");
}

C++的类型转换_第2张图片

可以看到,强制转换不管父类还是子类对象都会发生转换,而dynamic_cast只有原先指向子类时才会发生转换

注意:
强制类型转换关闭或者挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方式达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。
强烈建议:避免使用强制类型转换

三. RTTI

RTTI:Run-time Type identification的简称,即:运行时类型识别

有以下三种方式:

  1. typeid:通过name()函数获取类型名称的字符串
    C++的类型转换_第3张图片

  2. dynamic_cast:可以识别一个指针/引用,指向的是父类对象还是子类对象

  3. decltype:自动类型推导
    和auto类似,但是decltype是通过其他对象获取类型

auto x=1;//auto通过=号右边推导
decltype(x) y=1;//decltype通过x推导

auto要求变量必须初始化,因为auto根据变量的初始值来推导变量类型,如果不初始化,变量的类型就无法推导。
而decltype不需要初始化,所以decltype可以适用于只要自动推导类型的场景

比如如下场景:

function<int> add=[](int a,int b)->int{ return a+b; };
set<int,decltype(add)> s;

结束语

感谢你的阅读

如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

你可能感兴趣的:(C++学习笔记,c++,java,jvm)