C++ - 四种强制类型转换

一、隐式类型转换和显示类型转换

当等号两边的类型不同的时候、形参与实参类型不匹配的时候、返回值类型与接收返回值类型不一致时,就需要发生类型转化
而类型转换又分为隐式类型转换和显示类型转换

#include <stdio.h>
#include <stdlib.h>

int main()
{
	// 隐式类型转换
	int Ival = 1;
	double Dval = Ival;

	// 显示类型转换
	int* p = &Ival;
	int pi = p;// error
	int pi = (int)p;

	return 0;
}

隐式类型转换是编译器在编译阶段自动进行,能转就转,不能转就编译失败。而显示类型转换就要我们自己处理。 

 

二、C++的四种强制类型转换

上面的两种类型转换是C语言风格的,存在一些缺点。隐式类型转换会造成精度的丢失。而显示类型转换则会导致转换不清晰(不知道谁转化过来)。所以C++提供了规范的四种类型转换

 

2.1 static_cast

  • 相似转化

如果想要进行相似类型的转换,编译器隐式执行的任何类型转换都可用。但是如果是两个不相关的类型就不能转换

int main()
{
	int i = 0;
	double d = static_cast<int>(i);
	int* p = nullptr;
	int pi = static_cast<int>(p);// error
	return 0;
}

 

2.2 reinterpret_cast

  • 不同类型转化

上面我们用指针类型转化成整型出现错误,而这种不同类型的转换要用reinterpret_cast

int main()
{
	int i = 0;
	double d = static_cast<int>(i);
	int* p = nullptr;
	int pi = static_cast<int>(p);// error

	int pi = reinterpret_cast<int>(p);// correct
	return 0;
}

 

2.3 const_cast

  • 去除const属性

使用const_cast的主要目的是为了去除一个const变量的const,方便赋值。

int main()
{
	const int i = 1;
	int* p = const_cast<int*>(&i);
	*p = 3;
	cout << i << endl;
	return 0;
}

这里的结果需要注意一下:

这里是因为编译器把这个变量放到了寄存器中,我们修改的是内存中的数据,不影响寄存器,我们可以加上volatile关键字(每次都去内存中取)来看看:

int main()
{
	volatile const int i = 1;
	int* p = const_cast<int*>(&i);
	*p = 3;
	cout << i << endl;
	return 0;
}

 

2.4 dynamic_cast

  • 向下转换

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

在前面的文章【C++】继承中讲过,子类对象赋值给父类 对象/指针/引用,这里有个形象的说法叫切片或者切割,寓意把派生类中父类那部分切来赋值过去。

但是如果我们直接把父类类传递给子类,会不安全,因为父类转给子类会多开一份空间,可能会越界访问。

class A
{
public:
	virtual void f() {}
public:
	int _a = 0;
};

class B : public A
{
public:
	int _b = 0;
};

void fun(A* pa)
{
	B* pb = (B*)pa;

	pb->_a++;
	pb->_b++;

}

int main()
{
	A a;
	B b;
	fun(&a);
	fun(&b);
	return 0;
}

而加上dynamic_cast后如果转化失败就会返回空指针,让我们检查:

class A
{
public:
	virtual void f() {}
public:
	int _a = 0;
};

class B : public A
{
public:
	int _b = 0;
};

void fun(A* pa)
{
	B* pb = dynamic_cast<B*>(pa);
	cout << pb << endl;
	if (pb)
	{
		pb->_a++;
		pb->_b++;
	}
}

int main()
{
	A a;
	B b;
	fun(&a);
	fun(&b);
	return 0;
}

但是这里要注意dynamic_cast只能用于父类含有虚函数的类

 

三、总结

4种类型转换的应用场景?

  1. static_cast用于相近类型的类型之间的转换,编译器隐式执行的任何类型转换都可用static_cast。
  2. reinterpret_cast用于两个不相关类型之间的转换。
  3. const_cast用于删除变量的const属性,方便赋值。
  4. dynamic_cast用于安全的将父类的指针(或引用)转换成子类的指针(或引用)。

 

 

======================================================================================

c++强制类型转换

在C++中,强制类型转换是通过类型转换操作符来实现的。这些操作符可以让你明确地将一个表达式转换为特定的类型。

下面是几种常见的C++强制类型转换:

  1. static_cast:用于非多态类型的转换。

double d = 3.14;
int i = static_cast<int>(d); // 将double转换为int
  1. dynamic_cast:用于多态类型的转换,主要用于向下类型转换(从基类指向派生类的指针/引用),会检查转换的有效性,如果转换不安全,则无法进行转换。

class Base { virtual void dummy() {} };
class Derived : public Base { /* ... */ };
Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b); // 将Base指针转换为Derived指针
  1. const_cast:用于去除 const 属性或者添加 const 属性。

const int ci = 10;
int* modifiable = const_cast<int*>(&ci); // 去除const属性
  1. reinterpret_cast:用于将任何指针类型转换成任何其他的指针类型,可能也包括指针与足够大的整数类型之间的转换。

int* p = new int(65);
char* ch = reinterpret_cast<char*>(p); // 将int指针转换为char指针

volatile:用于访问某些硬件寄存器或者并发编程中的内存共享数据。

选择哪种类型转换取决于你需要进行何种转换以及转换的对象是什么。在使用强制类型转换时,需要确保转换的合理性,以避免转换导致的类型不匹配或运行时错误。

posted @ 2024-05-08 14:45  [BORUTO]  阅读(25)  评论(0编辑  收藏  举报