C语言的类型转换

C语言的类型转化分为两种:隐式类型转换和显式类型转换。
所谓隐式类型转换往往发生在二元运算符,通常会将类型相近的进行转换,譬如int转成double、int转成size_t,诸如此类:

int main()
{
	double x = 10;//int 转为double
	cout << x << endl;
	bool b= (1.6 > 1);//int转成double;
	cout << b << endl;
	cout << (-1 > sizeof(int)) << endl;//int转成size_t

	int y = 1.5;//double转为int
	cout << y << endl;

	return 0;
}
10
1
1
1

注意到sizeof()返回的是size_t类型,当-1转成size_t类型是比sizeof(4)大的。这也是刚开始敲代码常出bug的地方。

显式类型转换则是无法隐式转换,或想要主动转换:

int main()
{
	int* p = new int;
	size_t x = (size_t)p;//int*显式类型转换为int
	cout << x << endl;
	//double y=(double)p 类型相差太多了,int*不能直接转换成double。
	double y = *((double*)p);//但可以间接转换
	cout << y << endl;

	cout << 1 / 3 << endl;
	cout << (double)1 / 3 << endl;//转换成double除法

	delete p;
	return 0;
}

C++兼容C语言的类型转换

C++为了兼容C语言,C上能实现的类型转换C++自然也能实现。除此之外还可以从内置类型转换成自定义类型、自定义类型转换成自定义类型、自定义类型转换成内置类型。
前两者本质是调用自定义类型对应参数的构造函数, 后者则是需要实现特定重载函数:

class A
{
public:
	operator int()
	{
		return 10;
	}
};

int main()
{
	A a;
	cout << (int)a << endl;//自定义类型转换成内置类型
}

C语言的类型转换的缺点

C风格的转换格式很简单,但是有不少缺点的:

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

C++的四种类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:
static_cast、reinterpret_cast、const_cast、dynamic_cast

static_cast

static_cast其实就对应C语言的隐式类型转换:

class A
{
public:
	A(int a)
		:_a(a)
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	//C语言写法
	A a1 = 10;
	int x1 = 12.5;
	cout << x1 << endl << endl;

	//C++写法
	A a2 = static_cast<A>(20);
	int x2 = static_cast<int>(22.5);
	cout << x2 << endl;

	return 0;
}
10
12

20
22

reinterpret_cast

reinterpret_cast对应C语言的强制类型转换:

class A
{
public:
	operator int()
	{
		return 10;
	}
};

int main()
{
	//C语言写法
	int x = 10;
	int* p = &x;
	A a;
	
	int y = (int)p;
	int z = a;
	cout << y << endl << z << endl << endl;

	//C++写法
	int yy = reinterpret_cast<int>(p);
	int zz = static_cast<int>(a);
	cout << yy << endl << zz << endl;

	return 0;
}
1401945156
10

1401945156
10

注意转换类型匹配不上可是会报错哦:

	int yy = static_cast<int>(p);
	int zz = reinterpret_cast<int>(a);
 error C2440: “static_cast”: 无法从“int *”转换为“int”
 error C2440: “reinterpret_cast”: 无法从“A”转换为“int”

const_cast

const_cast就是删除常量属性的转换,主要用于指针:

int main()
{
	const int a = 520;
	const int* p = &a;
	//C语言写法
	int* pp = (int*)p;
	*pp = 1314;
	cout << a << endl << *pp << endl << endl;

	//C++写法
	int* ppp = const_cast<int*>(p);
	*ppp = 10000;
	cout << a << endl << *ppp << endl;

	return 0;
}
520
1314

520
10000

注意到a的值没有被改变,这实际上是编译器优化的结果。因为定义a的时候用了const,有的编译器就可能直接将a定义宏了。所以如果明确想要a的值可能改变需要加上关键字volatile

int main()
{
	volatile const int a = 520;
	volatile const int* p = &a;
	//C语言写法
	int* pp = (int*)p;
	*pp = 1314;
	cout << a << endl << *pp << endl << endl;

	//C++写法
	int* ppp = const_cast<int*>(p);
	*ppp = 10000;
	cout << a << endl << *ppp << endl;

	return 0;
}
1314
1314

10000
10000

dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

其实本质上是给那些原本从子类指针转成的父类指针一个回心转意的机会。
还需注意使用事项:

  1. dynamic_cast只能用于父类含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
class A
{
public:
	virtual void f() {}
};
class B : public A
{};

void fun(A* pa)
{
	// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
	B* pb1 = static_cast<B*>(pa);
	B* pb2 = dynamic_cast<B*>(pa);
	cout << "pb1:" << pb1 << endl;
	cout << "pb2:" << pb2 << endl;
}
int main()
{
	A a;
	B b;
	fun(&a);
	fun(&b);
	return 0;
}
pb1:00000072B60FF928
pb2:0000000000000000
pb1:00000072B60FF948
pb2:00000072B60FF948

可见这种情况使用reinterpret_cast还是有风险的,建议使用dynamic_cast。

RTTI

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

C++通过以下方式来支持RTTI:

  1. typeid运算符
  2. dynamic_cast运算符
  3. decltype

常见面试题

C++中的4中类型转化分别是

static_cast、reinterpret_cast、const_cast、dynamic_cast

说说4中类型转化的应用场景。

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

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐