C++的强制类型转换

文章目录

  • 前言
  • 1.dynamic_cast
  • 2.const_cast
  • 3.static_cast
  • 4.reinterpret_cast

前言

C++强制类型转换的格式有两种:

  • typename(value);
  • (typename)value;

第二种是C语言的风格,第一种C++风格,因为这种格式就好像是函数调用,更有感觉。

另外由于C语言中的强制类型转换并没有严格的限制,所以C++引入了四种强制类型转换运算符。可以根据不同的情况,选择合适的强制转换运算符。

1.dynamic_cast

该运算符的作用是在有继承关系的这种类层次结构中进行向上转换,不允许其他转换。

举个栗子:

class A {
...
};
class B : public A{
...
};

int main() {
	A* a;
	B* b;
	a = dynamic_cast<A*> (b);
	//b = dynamic_cast (a);  ERROR,只能向上转型
}

2.const_cast

有时候可能存在一种值,它大多数时候是常量,但有时又可以修改。这种情况下,将其定义为const,需要修改的时候使用const_cast进行转型。

举个栗子:(借用上面的类)

A a;
const A* pa = &a;
A* p = const_cast<A*> (pa); //这使得p称为一个可以用于修改a对象的内容的指针

对于const_cast,它只能在同类型之间转型,所以它更加安全,避免在改变某个对象的常量特征时不小心修改了它的类型。

Tips:
const_cast是可以改变指向一个值的指针,但更改了常量特征的指针所指向的那个值若是const的,仍然是不可以修改的。

3.static_cast

在第一种dynamic_cast类型转换符的作用下,是不可以将基类指针转换到派生类指针的,所以使用static_cast能够实现类似于这种的向下转换。比如可以将double转换为int。

由于对于数值类型的向下转换是可能出现精度损失的,因此使用static_cast强制转换就是告诉编译器我们是在知情并接受这样的精度损失的前提下进行的。

举个栗子:

A a;
B b;
...
B* pb = static_cast<B*> (&a);

static_cast还可以用来找回存在于void*指针中的值,比如:

double a = 3.14;
void* p = &a;	//指针p指向a,但无法通过它操作a
double *pb = static_cast<double*> (p); //转型后可以用pb对a操作

Tips:
当然向上转型也是可以的,对于类的强制转换仅限类与类之间是要有继承关系的,无关的类则无效。

4.reinterpret_cast

reinterpret_cast是可以进行无关的类型之间的转换的,它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的比特位。但这种转换的任意性必然存在很多问题,那么在什么情况下使用它是最重要的。

IBM的C++指南中规定Linux系统下的reinterpret_cast使用建议:

  • 从指针类型到一个足够大的整数类型
  • 从整数类型或者枚举类型到指针类型
  • 从一个指向函数的指针到另一个不同类型的指向函数的指针
  • 从一个指向对象的指针到另一个不同类型的指向对象的指针
  • 从一个指向类函数成员的指针到另一个指向不同类型的函数成员的指针
  • 从一个指向类数据成员的指针到另一个指向不同类型的数据成员的指针

总的来说,reinterpret_cast用于任意指针(或引用)类型之间的转换;以及将指针转换为足够大的整数类型;或者是将整数类型(或枚举类型)转换为指针类型(这种情况无视大小)。

但对于这样可以“乱搞”的类型转换符来说,如果不当的使用会让程序出现不必要的错误,那么它的正确打开方式或者它存在的意义到底是什么的呢?

查阅资料,读其他博客了解到,C++之父Bjarne Stroustrup的FAQ网页和MSDN的Visual C++都指出:错误的使用reinterpret_cast很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确使用reinterpret_cast方式。

这么说,它起到一个在过程中间先临时隐藏某种类型的作用,等到真正需要那个值的时候,再转回来。查阅资料发现,它的一个应用就是用来辅助哈希函数(代码转自MSDN的例子):

// expre_reinterpret_cast_Operator.cpp
// compile with: /EHsc
#include 
// Returns a hash code based on an address
unsigned short Hash( void *p ) {
	unsigned int val = reinterpret_cast<unsigned int>( p );
	return ( unsigned short )( val ^ (val >> 16));
}

using namespace std;
int main() {
	int a[20];
	for ( int i = 0; i < 20; i++ )
		cout << Hash( a + i ) << endl;
}

//如果-是64位的系统,可能需要将unsigned int改成 unsigned long才能运行。

在哈希函数中,操作整数肯定比拿着指针操作更直接方便。

Tips:
reinterpret_cast运算符不可以修改常量特征,即不可以删除const,另外不能将函数指针转换为数据指针,反之亦然。

你可能感兴趣的:(c++)