【C++】类型转换

C语言类型转换

1.

void Test1()
{
	int i = 1;
	//隐士类型转换(意义相近)
	double d = i;
	printf("%d	%.2f\n", i, d);

	int* p = &i;
	//显示类型转换(意义不相近,转换后值有意义)
	int address = (int)p;
	printf("%p	%d\n", p, address);
	printf("%x	%d", p, address);
}

在这里插入图片描述

2.

void Insert(size_t pos,char ch)
{
	size_t _size = 10;
	size_t end = _size - 1;
	while (end >= pos)
	{
		//_str[end + 1] = _str[end];
		--end;
	}
}
void Test1()
{
	Insert(5, 'a');
	Insert(0, 'a');//
}

在这里调用的时候就出问题,end不会小于0,改为int end也不行;
在这里插入图片描述
通过监视发现,明明end变成-1,但循环仍会进去,这里其实就是比较的时候发生了隐式类型转换,比较的时候end由int变为unsigned int;
此时C++后来在这里做了一些新的方法(旧的不能改)------四种类型转换,接着往下看…

四种类型转换

提出的目的,1了兼容C语言,由有自己特有的方式,2显示类型混在一起,不清晰;
3C++期望不要用这些对象,而是用以下四种类型转换替代它们;
前三种为兼容C语言强制类型转换

static_cast

静态转换(对应隐式类型转换,即意义相近的类型)
在这里插入图片描述

用于明确转换一种数据类型为另一种,包括基本数据类型、类指针和引用等。
可以用于类层次结构中的向上和向下转换,但不会进行运行时检查,因此可能不安全。
总结:它有错误会在编译时指出,运行时不会起作用

double d = 3.14;
int i = static_cast<int>(d);

reinterpret_cast

重新解释转换
在这里插入图片描述
对p的意义重新解释

用于将一个指针或引用转换为另一种不同类型的指针或引用。
它不会进行类型检查或添加/移除任何常量性,仅仅是重新解释数据
非常危险,一般情况下应该避免使用,除非非常清楚转换的含义和后果。

int num = 10;
void* voidPtr = &num;
int* intPtr = reinterpret_cast<int*>(voidPtr);

const_cast

常量转换(对应强制类型转换)

用于去除指针或引用的常量性。
可以用于添加或移除常量性但不应该用于修改原本非常量对象的值。

int main()
{
	const int a = 2;
	int* p = const_cast<int*>(&a);
	*p = 5;
	cout << a << endl;
	cout << *p << endl;
	return 0;
}

在这里插入图片描述原因:编译器优化,它对const变量认为不会变,故而直接加载到了寄存器(有的编译器直接用宏那种处理方式直接替换,如vs),读的时候它会去寄存器去取(即使a的值在内存中已被修改);而调试器拿数据的时候在内存中取数据;

在这里插入图片描述
补:调试的时候,是另一个进程去取调试信息的;
看上面截图,截图红色框有问题,看底下的 push 2这里流中直接将2压入栈中的。

如何处理呢?加关键字volatile,让编译器不要写死
在这里插入图片描述

dynamic_cast

动态转换(C++独有),向下转换

于在类层次结构中进行安全的向上和向下转换。
只能用于指向对象的指针和引用,并且只能用于具有虚函数的类
在向下转换时,如果转换是有效的,则返回指向目标类型的指针否则返回空指针

先看之前的类型转换,都会产生临时变量
在这里插入图片描述在这里插入图片描述C语言强转
在这里插入图片描述
C++安全转换
在这里插入图片描述
在这里插入图片描述

class A
{
public:
	virtual void f(){}
	int _a = 0;
};
class B :public A 
{
public:
	int _b = 0;
};
void fun(A* pa)
{
	B* pb = dynamic_cast<B*> (pa);
	//B* pb = (B*)pa;
	if (pb)
	{
		cout << "转换成功" << endl;
		cout << pb->_a << ":" << pb->_b << endl;
	}
	else
	{
		cout << "转换失败" << endl;
		cout << pa->_a << endl;
	}
}
int main()
{
	A* aa = new A;
	B* bb = new B;

	fun(aa);
	fun(bb);
	return 0;
}

这里相信已经很清楚的介绍了dynamic_cast,那接下来我们关于它的变幻,在进行深入玩转
在这里插入图片描述

在这里插入图片描述

class A1
{
public:
	//virtual void f() {}
	int _a = 0;
};
class A2
{
public:
	//virtual void f() {}
	int _a = 0;
};
class B :public A1,public A2
{
public:
	int _b = 0;
};

int main()
{
	B bb;
	A1* ptr1 = &bb;
	A2* ptr2 = &bb;
	cout << ptr1 << endl;
	cout << ptr2 << endl << endl;

	B* pb1= (B*)ptr1;
	B* pb2= (B*)ptr2;
	cout << pb1 << endl;
	cout << pb2 << endl << endl;

	//B* pbb1 = dynamic_cast<B*>(ptr1);
	//B* pbb2 = dynamic_cast<B*>(ptr2);
	//cout << pbb1 << endl;
	//cout << pbb2 << endl << endl;

	return 0;
}

可见C语言的写法也会将切片的偏移量在向回转的时候,跳回去且不受虚函数限制;

RTTI

Run Time Type Identification:运行时类型识别

之前在智能指针学过一个RAII:资源获得初始化

typeid:对象类型字符串
dynamic_cast:识别父类指针是指向子类对象address还是父类对象nullptr
decltype:推导对象类型,可以用来定义别的对象

  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值