【初阶与进阶C++详解】第二十五篇:类型转换(static_cast+reinterpret_cast+const_cast+dynamic_cast+RTTI)

发布于:2022-11-28 ⋅ 阅读:(519) ⋅ 点赞:(0)

🏆个人主页企鹅不叫的博客

​ 🌈专栏

⭐️ 博主码云gitee链接:代码仓库地址

⚡若有帮助可以【关注+点赞+收藏】,大家一起进步!

💙系列文章💙

【初阶与进阶C++详解】第一篇:C++入门知识必备

【初阶与进阶C++详解】第二篇:C&&C++互相调用(创建静态库)并保护加密源文件

【初阶与进阶C++详解】第三篇:类和对象上(类和this指针)

【初阶与进阶C++详解】第四篇:类和对象中(类的六个默认成员函数)

【初阶与进阶C++详解】第五篇:类和对象下(构造+static+友元+内部类

【初阶与进阶C++详解】第六篇:C&C++内存管理(动态内存分布+内存管理+new&delete)

【初阶与进阶C++详解】第七篇:模板初阶(泛型编程+函数模板+类模板+模板特化+模板分离编译)

【初阶与进阶C++详解】第八篇:string类(标准库string类+string类模拟实现)

【初阶与进阶C++详解】第九篇:vector(vector接口介绍+vector模拟实现+vector迭代器区间构造/拷贝构造/赋值)

【初阶与进阶C++详解】第十篇:list(list接口介绍和使用+list模拟实现+反向迭代器和迭代器适配)

【初阶与进阶C++详解】第十一篇:stack+queue+priority_queue+deque(仿函数)

【初阶与进阶C++详解】第十二篇:模板进阶(函数模板特化+类模板特化+模板分离编译)

【初阶与进阶C++详解】第十三篇:继承(菱形继承+菱形虚拟继承+组合)

【初阶与进阶C++详解】第十四篇:多态(虚函数+重写(覆盖)+抽象类+单继承和多继承)

【初阶与进阶C++详解】第十五篇:二叉树搜索树(操作+实现+应用KVL+性能+习题)

【初阶与进阶C++详解】第十六篇:AVL树-平衡搜索二叉树(定义+插入+旋转+验证)

【初阶与进阶C++详解】第十七篇:红黑树(插入+验证+查找)

【初阶与进阶C++详解】第十八篇:map_set(map_set使用+multiset_multimap使用+模拟map_set)

【初阶与进阶C++详解】第十九篇:哈希(哈希函数+哈希冲突+哈希表+哈希桶)

【初阶与进阶C++详解】第二十篇:unordered_map和unordered_set(接口使用+模拟实现)

【初阶与进阶C++详解】第二十一篇:哈希应用(位图实现应用+布隆过滤器增删查优缺点+海量数据面试题)

【初阶与进阶C++详解】第二十二篇:C++11新特性(列表初始化+变量类型推到+右值引用+新增默认成员函数+可变模板参数+lambda表达式+包装器function_bind)

【初阶与进阶C++详解】第二十三篇:异常(异常抛出+异常捕获+异常优缺点)

【初阶与进阶C++详解】第二十四篇:智能指针(内存泄漏+RAII+auto_ptr+unique_ptr+shared_ptr+weak_ptr+定制删除器)



💎一、C语言中的类型转换

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

  • 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
  • 显式类型转化:需要用户自己处理
void Test ()
{
	int i = 10;
	// 隐式类型转换
	double d = i;
	printf("%d, %.3f\n" , i, d);
	int* ptr = &i;
	// 显示的强制类型转换
	int address = (int) ptr;
	printf("%x, %d\n" , ptr, address);
}

缺陷:

  1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰

💎二、C++强制类型转换

🏆1.static_cast

static_cast用于相近类型之间的类型转换

int main()
{
	double d = 13.14;
 //静态转换:static_cast
	//支持任何隐式类型转换  但它不支持两个不相关的类型进行强制转换
	int a = static_cast<int>(d);
	cout<<a<<endl;
	return 0;
}

🏆2.reinterpret_cast

reinterpret_cast用于不相近类型之间的类型转换

int main ()
{  

 int i = 10;
 //强制类型转换:reinterpret_cast
 //重新解释,用于将一种类型转换为另一种不同的类型
 int* pi = &i;
 int i2 = reinterpret_cast<int> (pi);
	return 0;
}

🏆3.const_cast

const_cast常用于删除变量的const属性,即用于将const变量转为非const变量,方便赋值

int main ()
{  
	const int ci = 10;
	const int* pci = &ci;
	int* pci2 = const_cast<int*> (&ci);
	*pci2 = 20;
	cout << ci << endl;   //10
	cout << *pci2 << endl;//20
	cout << *pci << endl; //20
	cout << "adress" << endl;  //下面三个地址都一样 编译器做了优化
	cout << &ci << endl;   
	cout << pci2 << endl;
	cout << pci << endl; 
 return 0;
}    

🏆4.dynamic_cast

dynamic_cast 用于将一个父类对象的指针转换为子类对象的指针或引用(动态转换)只能用于含有虚函数的父类(非多态不能使用dynamic_cast),规范向下转换,会检查是否能转换成功,能成功则转换,不能则返回0

  • 向上转型:子类对象指针->父类指针/引用(不需要转换,赋值兼容规则)
  • 向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)
class A
{
public:
	virtual void f(){}
};

class B : public A
{};
void fun(A* pa)
{
	B* ptr = dynamic_cast<B*>(pa);
    //用下面这两个转换,A转B,B转B都会成功,但是不安全
	//B* ptr = reinterpret_cast<B*>(pa);
	//B* ptr = (B*)pa;

	if (ptr)
	{
		cout << "转换成功" << ptr << endl;
	}
	else
	{
		cout << "转换失败" << ptr << endl;
	}
}

int main()
{
	A a;
	B b;
	fun(&a);//转换失败00000000,子类转换成父类,可能导致越界,不安全所以失败
	fun(&b);//转换成功(某个地址)
	return 0;
}

🏆5.explicit

explicit关键字阻止经过转换构造函数进行的隐式转换的发生

//explicit
class A
{
public:
	//explicit会阻止单参构造的隐式类型转换
 //编译器报错,不能从int类型转换到A类型
	explicit A(int a)
		:_a(a)
	{
		cout << "A(int a) " << endl;
	}
private:
	int _a;
};

int main()
{
	//explicit关键字会阻止单参构造函数进行的隐式转换
	A e = 10;
	return 0;
}

🏆6.RTTI

RTTI:Run-time Type identification的简称,即:运行时类型识别
C++通过以下方式来支持RTTI:

  1. typeid运算符(返回的是类型的字符串typeid(对象).name()
  2. dynamic_cast运算符
  3. decltype,获取对象具体类型

💎三、小结

  • 去const属性用const_cast
  • 基本类型转换用static_cast
  • 多态类之间的类型转换用dynamic_cast
  • 不同类型的指针类型转换用reinterpret_cast

强烈建议:避免使用强制类型转换


本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到