C++强制类型转换

本文深入探讨C++中的四种类型转换:C语言风格的强制类型转换、const_cast、dynamic_cast和static_cast,以及reinterpret_cast。文章通过实例讲解每种转换的特点和适用场景,并介绍了explicit关键字的使用和类型提升的概念。
部署运行你感兴趣的模型镜像

C语言的强制类型转换----可读性差,十分坑人

先看个笔试选择常考题,看下面代码,写出运行结果:

#include<iostream>
using namespace std;
int main()
{
	const int a = 10;
	int*p =(int*) &a;
	*p = 20;
	cout << a << endl;
	return 0;
}

在这里插入图片描述
输出结果是仍然是10,但是内存中已经是修改后的20。What fuck?事实胜于雄辩,我们知道在C++中被const修饰的变量就是常量,所以,这里显示使用了C语言的强制类型转换,达成了修改意愿。

C语言的中强制类型转换分为隐式类型转换和显示的强制类型转换

直接看栗子

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	double b = 20;
	b = a;
	cout << a << endl << b << endl;
	system("pause");
	return 0;
}

在这里插入图片描述
int类型的a赋值给double类型的b,是允许的,语法上认为,它们都是相近类型,都是表示数值,所以允许它们直接隐式类型转换。

如果你想把不相近类型强制转换,也许显示调用强制类型转换会有效果。

#include<iostream>
#include<string>
using namespace std;
int main()
{
	int a = 10;
	int*p = &a;

	int b = (int)p;//把指针类型转换成整形
	system("pause");
	return 0;
}

简单了解了C语言的类型转换,我们再来看看这个题。既然强制类型转换了,为什么输出结果还是10呢?因为const,C++中,编译器认为const修饰的值是常量,所以它会将这个常量放在寄存器中,当需要使用时候,它就从寄存器直接取出来这个初始化时候的常量。
在这里插入图片描述
还真是这样,为了让这货好好干活,别再偷懒优化。我们可以在a变量前加volatile,让它每次用a的值都去内存中取,保证a值得内存可见性。
在这里插入图片描述

const_cast----删除const属性的转换

const_cast最常用的用途就是删除变量的const属性,简单明了,不用考虑太多。
在这里插入图片描述

dynamic_cast----运行时类型识别(仅用于多态场景)

dynamic_cast用于将一个父类对象的指针转换为子类对象的指针或引用(动态转换)。在多态中,我们知道,子类对象、指针、引用都可以用父类对象或者指针去接收,这由语法自动完成切片。不太懂的可以看看这里。https://blog.youkuaiyun.com/Vickers_xiaowei/article/details/82750286#_98

向上转型:子类对象指针->父类指针/引用(不需要转换,自动完成切片)
向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)

  1. dynamic_cast只能用于含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
#include<iostream>
using namespace std;

class Person{
protected:
	string _name;
	virtual void Print()
	{
		cout << "I am the father" << endl;
	}
};

class Student :public Person
{
public:
	int _num;
	virtual void Print()
	{
		cout << "I am the son" << endl;
	}
};
void Func(Person* p)
{
	//父类对象指针->子类指针/引用
	Student* sp = dynamic_cast<Student*>(p);//只允许子类对象指针转换
	sp->Print();
}
int main()
{
	Person p;
	Student s;
	//Func(&p);//使用dynamic_cast,不能将父类指针转换成子类指针,防止了越界行为
	Func(&s);
	system("pause");
	return 0;
}

涉及多态的类型转换最好使用dynamic_cast,防止越界。

static_cast ----相关类型转换

static_cast用于非多态类型的转换(静态转换) ,任何标准转换都可以用它,但它 不能用于两个不相关的类型进行转换。 这里所谓的相关类型和C语言中可以隐式转换的相近类型概念基本一样,C++使用static_cast更加明显,增强了可读性。

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int*p = static_cast<int*>(&a);
	*p = 20;
	cout << a << endl;
	system("pause");
	return 0;
}

reinterpret_cast----不相关类型转换

reinterpret_cast操作符用于将一种类型转换为另一种不同的类型。与C语言的强制转换可读性更好。

#include<iostream>
#include<string>
using namespace std;
int main()
{
	int a = 10;
	int*p = &a;

	int b = reinterpret_cast<int>(p);
	system("pause");
	return 0;
}

少用类型转换,多使用C++标准的强制转换

拓展1):explicit关键字

对于单参数构造函数会将单参数隐式类型转换。

#include<iostream>
using namespace std;

class A
{
public:
	A(int a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& a)
	{
		cout << "A(const A& a)" << endl;
	}
private:
	int _a;
};

int main()
{
	A a1(1);
	// 隐式转换-> A tmp(1); A a2(tmp);
	A a2 = 1;
	system("pause");
}

上述代码将int类型隐式转换成了自定义类型A,如果不想让这样的隐式类型转换,对于单参数类型转换,explicit关键字阻止经过转换构造函数进行的隐式转换的发生。
在这里插入图片描述

拓展 2)类型提升

#include<iostream>
using namespace std;

int main()
{
	size_t pos = 0;
	int end= 3;
	while (end >= pos)
		--end;
	system("pause");
	return 0;
}

int类型的end与size_t类型的pos在比较时候,会将end的int类型提升到size_t,类型提升总是提升到范围大的那一个,所以上面无符号的-1比0大,上面代码会陷入死循环。

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

### C++ 强制类型转换方法及其使用指南 #### 新式转型概述 在C++中,强制类型转换被称为新式转型,区别于C语言中的旧式转型。新式转型提供了四种不同的关键字来执行特定类型的转换操作:`static_cast`、`dynamic_cast`、`const_cast` 和 `reinterpret_cast`[^1]。 #### Static Cast (静态转换) `static_cast` 是一种编译期检查的类型转换机制,适用于基本数据类型间的相互转换以及具有继承关系的对象之间安全的方向上的转换。例如: ```cpp double dValue = 3.14; int iValue = static_cast<int>(dValue); ``` 对于指针或引用来说,当基类和派生类存在单根继承体系时可以实现向下转型(即从基类到派生类),但是这种情况下应该优先考虑使用更安全的方式——`dynamic_cast`。 #### Dynamic Cast (动态转换) `dynamic_cast` 主要用于处理多态对象之间的转换,在运行期间能够判断两个类型间是否存在合法的关系并返回相应结果。如果尝试非法的操作,则会抛出异常或者返回null指针取决于具体场景。这使得它成为最安全但也可能是性能开销最大的选项之一: ```cpp Base* basePtr = new Derived(); Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); if(derivedPtr != nullptr){ // 成功转换... } else{ // 转换失败... } ``` 此功能特别适合用来验证是否可以从某个已知接口获取更加具体的实例化版本[^3]。 #### Const Cast (常量属性修改) `const_cast` 的作用在于移除变量声明时所附加的 const 或 volatile 属性。虽然有时确实有必要这样做,但在大多数时候应当尽量避免改变原本设计意图下的不可变性约束,因为这可能会引发未定义行为的风险。 ```cpp void someFunction(const int& value){ int* nonConstValue = const_cast<int*>(&value); (*nonConstValue)++; } // 注意上述做法并不推荐除非有充分理由证明其安全性。 ``` #### Reinterpret Cast (重新解释位模式) 最后是 `reinterpret_cast`, 它允许程序员直接操纵底层二进制表示形式来进行几乎任何种类的数据视图变换。然而由于缺乏语义层面的理解和支持,误用该特性极易造成难以调试的问题甚至危及整个系统的稳定性。因此仅限于那些真正需要低级控制的应用场合下谨慎采用,并且通常只会在非常特殊的情况下才会涉及到此类操作[^2][^4]: ```cpp uintptr_t rawAddress = reinterpret_cast<uintptr_t>(&someObject); void* genericPointer = reinterpret_cast<void*>(rawAddress); ``` 综上所述,每种类型转换都有各自适用范围内的最佳实践指导原则,合理选择合适的工具可以帮助开发者写出既高效又可靠的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值