您的位置:首页 > 编程语言 > C语言/C++

C++:关于C++的四个类型转换运算符

2015-04-10 11:03 253 查看
C++严格地限制允许的类型转换,并添加了4个类型转换运算符:

1)dynamic_cast
2)const_cast
3)static_cast
4)reinterpret_cast
一,dynamic_cast运算符

假设:

class High{};
class Low{};
Hign * ph;
Low * pl;
当且仅当 Low 是High的可访问基类(直接或间接)时,下面的语句才将一个Low*指针赋给pl

pl = dynamic_cast<Low*>(ph);


否则上句将空指针赋给pl.

综述:dynamic_cast运算符用途是,使得能够在类层次结构中进行向上转换(由于是is-a关系,这样的转换是安全的),不允许其它转换。

二,const_cast 运算符

这里解释下volatile:

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。

精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

关于volatile的思考:

1)一个参数既可以是const还可以是volatile吗?解释为什么。 

2)一个指针可以是volatile 吗?解释为什么。 

3)下面的函数有什么错误:

int square(volatile int *ptr)
{
return *ptr * *ptr;
}
答案: 

1)是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 

2)是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 

3)这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码: 

int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:

long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
const_cast 运算符该运算符用于执行只有 一种用途的类型转换,即改变值为 const 或 volatile.

表达式:const_cast<type_name>(experssion)

如果类型的其它方面也被修改,则上述类型的转换将出错,也就是说:

除了const 与volatile特征(有或无)可以不同外,type_name与expression的类型必须相同。

还是假设:High 与 Low 是两个类

High high;
const High * ph = &high;
High * ph2 = const_cast<High *>(ph); // valid  -- High *  与 const Hign *,忽略const,相同
const Low * pl = const_cast<const Low *>(ph); // invalid -- const Low * 与 const Hign *,忽略const,不同
提供const_cast运算符的原因:

有时候可能需要这样一个值,它在大多数时是常量,但有时又要是可以修改的。

在这种情况下,可将这个值申明为const,并在修改它的时候,使用cosnt_cast。

当然也可以用通用的类型转换,但通用类型转换可以同时改变类型。

High high;
const High * ph = &high;
High * ph2 = (High *)ph; // valid
Low * pl = (Low *)ph; // also valid
由于编程时可能同时改变类型与常量特征,因此const_cast运算符更安全。

const_cast 不是万能的,它可以修改指向一个值的指针,但可能无法修改const的值。
例:

#include <iostream>
using std::cout;
using std::endl;
void change(const int * pt, int n);

int main()
{
int pop1 = 38383; //非const值
const int pop2 = 2000; //const值

cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
change(&pop1, -103);
change(&pop2, -103);
cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
return 0;
}

void change(const int * pt, int n) //都用一个const类型的指针指向pop1,pop2
{
int * pc;
pc = const_cast<int *>(pt);
*pc += n;
}
结果:
pop1, pop2: 38383, 2000
pop1, pop2: 38280, 2000
请按任意键继续. . .
上述结果说明了:

const_cast 可以删除 const int * pt 中的const,

但如果pt指向的值也是const,则编译器可能禁止修改它。

三,static_cast 运算符

表达式: static_cast<type_name>(expression)

仅当 type_name 可以被隐式转换为 expression 或 expression 可被隐式转换为 type_name所属的类型时,上述转换才合法,否则出错。

假设Hign是Low的基类,Pond是一个无关的类,则从High到Low的转换,从Low到High的转换都是合法的,但从Low到Pond的转换是不允许的。

High high;
Low low;
High * ph = static_cast<High *>(&low); // valid
Low * pl = static_cast<Low *>(&high); // valid
Pond * pp = static_cast<Pond *>(&low); // invalid

四,reinterpret_cast 运算符

表达式:reinterpret_cast<type_name>(expression)

该运算符用于天生危险的类型转换,它不允许删除const,但会做其它操作。

示例:

struct dat
{
short a;
short b;
};
long value = 0xA224B118;
dat * pd = reinterpret_cast<dat *>(&value);
std::cout << hex << pd->a; //display first 2 bytes of value注:不同的操作系统在存储多字节整型时,可能以不同的顺序存储其中的字节。
reinterpret_cast 运算符并不支持所有的类型转换。

如:

1)可以将指针类型转换为足以存储指针表示的整型,但不能将指针转换为更小的整型或浮点型。

2)不能将函数指针转换为数据指针。

下面是对是错:

char ch = char(&d);

在C中是允许的,但在C++中通常不允许,因为char类型都太小,不能存储指针。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: