C++相对C更严格地限制允许的类型转换,并添加4个类型转换运算符,是转换过程更规范:
* dynamic_cast;
* const_cast;
* static_cast;
* reinterpret_cast。
【dynamic_cast运算符】
假设High和Low是两个类,而ph和pl的类型分别是High*和Low*,则仅当Low是High的可访问基类(直接或间接)时,下面的语句才将一个Low*指针赋给pl:
pl = dynamic_cast<Low *> ph;
否则,该与据将空指针赋给pl。通常,该运算符的语法如下:
dynamic_cast < type-name > (expression)
该运算符的用途是,使得能够在类层析结构中进行向上转换(由于is-a关系,这样的类型转换是安全的),而不允许其他转换。
【const_cast运算符】
const_cast运算符用于执行只有一种用途的类型转换,即改变值为const或volatile,其语法与dynamic_cast运算符相同。
const_cast < type_name > (expression)
如果类型的其他方面也被修改,则上述类型转换将出错。也就是说,除了const或volatile特征(有或无)可以不同外,type_name和expression的类型必须向同。再次假设High和Low是两个类:
High bar;
const High * pbar = &bar;
...
High * pb = const_cast<High *> (pbar); // valid
const Low * pl = const_cast<const Low *> (pbar); // invalid
第一个类型转换使得*pb称为一个可用于修改bar对象值的指针,它删除const标签。第二个类型转换是非法的,因为它同时尝试将类型从const High*改为const Low*。
提供运算符的原因是,有时候可能需要这样一个值,它在大多数时候是常量,而有时又是可以修改的。在这种情况下,可以将这个值声明为const,并在需要修改它的时候,使用const_cast。这也可以通过类型转换来实现,单通用转换也可以同时改变类型(这里的意思是const_cast不能同时改变类型):
High bar;
const High * pbar = &bar;
...
High * pb = (High *) (pbar); // valid
Low * pl = (Low *) (pbar); // also valid
由于编程时可能无意间同时该便类型和常量特征,因此使用const_cast运算符更安全。
【static_cast运算符】
static_cast运算符的语法与其他类型转换运算符相同:
static_cast < type_name > (expression)
仅当type_name可被隐式转换为expression所属的类型或expression可被隐式转换为type_name所属的类型时,上述转换才是合法的,否则将出错。假设High是Low的基类,而Pond是一个无关的类,则从High到Low的转换、从Low到High的转换都是合法的,而从Low到Pond的转换是不允许的:
High bar;
Low blow;
...
High *pb = static_cast<High *> (&blow); // valid upcast
Low * pl = static_cast<Low *> (&bar); // valid downcast
Pond * pmer = static_cast<Pond *> (&blow); // invalid, Pond unrelated
第一种转换是合法的,因为向上转换可以显式地进行。第二种转换是从基类指针到派生类指针,在不进行显式类型转换的情况下,将无法进行。单由于无需进行类型转换,便可以进行另一个方向的类型转换,因此使用static_cast来进行向下转换是合法的。
同理,由于无须进行类型转换,枚举值就可以被转换为整型,所以可以用static_cast将整型转换为枚举型。同样,可以使用static_cast将double转换为int、将float转换为long以及其他各种数值转换。
【reinterpret_cast运算符】
reinterpret_cast运算符用于天生危险的类型转换。它不允许删除const,但会执行其他令人生厌的操作。有时程序员必须做一些依赖于实现的、令人生厌的操作,使用reinterpret_cast运算符可以简化对这种行为的跟踪工作。该运算符的语法与另外3个相同:
reinterpret_cast < type-name > (expression)
下面是一个使用示例:
struct dat {short a; short b;};
long value = 0xA224B118;
dat * pd = reinterpret_cast< dat * > (&value);
cout << hex << pd->a; // display first 2 bytes of value
通常,这样的转换适用于依赖于实现的底层编程技术,是不可移植的。例如,不同系统在存储多字节整型时,可能以不同的顺序存储其中的字节。
然而,reinterpret_cast运算符并不支持所有的类型转换。例如,可以将指针类型转换为足以存储指针表示的整型,单不能将指针转换为更小的整型或浮点型。另一个限制是,不能将函数指针转换为数据指针,反之亦然。
在C++中,普通类性转换也受到限制。基本上,可以执行其他类型转换可执行的操作,加上一些组合,如static_cast或reinterpret_cast后跟const_cast,但不能执行其他转换。因此,下面的类型转换在C语言中是允许的,但在C++中通常不允许,因为对于大多数C++实现,char类型都太小,不能存储指针:
char ch = char (&d); // type cast #2 - convert address to a char