c++ primer plus 第15章友,异常和其他 类型转换运算符15.5

c++ primer plus 第15章友,异常和其他 类型转换运算符15.5

c++ primer plus 第15章友,异常和其他 类型转换运算符15.5


类型转换运算符15.5

在 C++的创始人 Bjamne Stroustrup看来,C语言中的类型转换运算符太过松散。例如,请看下面的代码:

struct Data
{
	double data[200];
};

struct Junk
{
int junk[100];
};

Data d={2.5e333.5e-1920.2e32);
char *pch=(char *)(&d);//type cast #l-convert to stringchar ch=char(&d);//type cast #2-convert address toachar//type cast #3-convert to Junk pointer
Junk *pj=(Junk *)(&d);
}

首先,上述3种类型转换中,哪一种有意义?除非不讲理,否则它们中没有一个是有意义的。其次,
这3种类型转换中哪种是允许的呢?在C语言中都是允许的。对于这种松散情况,Stroustrop采取的措施是,更严格地限制允许的类型转换,并添加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 *>phi

否则,该语句将空指针赋给p1。通常,该运算符的语法如下:

dynamic_cast<type-name >(expression)

该运算符的用途是,使得能够在类层次结构中进行向上转换(由于is-a关系,这样的类型转换是安全的),而不允许其他转换。
const _cast 运算符用于执行只有一种用途的类型转换,即改变值为const或volatile,其语法与dynamic cast 运算符相同:

const_cast<type-name >(expression)

如果类型的其他方面也被修改,则上述类型转换将出错。也就是说,除了const或 volatile 特征(有或无)可以不同外,type_name和expression的类型必须相同。再次假设High和Low是两个类

Hiqh bar;
const High*pbar =&bar;
High *pb=const_cast<High *>(pbar);// validconst Low*pl=
const cast<const ow*>(pbar);// invalid

第一个类型转换使得pb成为一个可用于修改 bar 对象值的指针,它删除 const 标签。第二个类型转换
是非法的,因为它同时尝试将类型从constHigh
改为const Low*。提供该运算符的原因是,有时候可能需要这样一个值,它在大多数时候是常量,而有时又是可以修改的。在这种情况下,可以将这个值声明为const,并在需要修改它的时候,使用const_cast。这也可以通过通用类型转换来实现,但通用转换也可能同时改变类型:

Hiqh bar;
const High*pbar =&bar;
High*pb=(High*)(pbar);
Low *pl=(Low*)(pbar);
// valid
// also valid

由于编程时可能无意间同时改变类型和常量特征,因此使用constcast运算符更安全。const cast不是万能的。它可以修改指向一个值的指针,但修改const值的结果是不确定的。程序清单15.19的简单示例阐明了这一点:

程序清单15.19 constcast.cpp

// constcast.cpp -- using const_cast<>
#include <iostream>
using std::cout;
using std::endl;

void change(const int * pt, int n);

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

    cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
    change(&pop1, -103);
    change(&pop2, -103);
    cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
    // std::cin.get();
    return 0;
}

void change(const int * pt, int n)
{
    int * pc;
  
    pc = const_cast<int *>(pt);
    *pc += n;
 
}

const_cast 运算符可以删除 constint*pt中的const,使得编译器能够接受 change( )中的语句:

*pC += n;

但由于 pop2 被声明为const,因此编译器可能禁止修改它,如下面的输出所示:

pop1,pop2:383832000
pop1,pop2:382802000

正如您看到的,调用change()时,修改了pop1,但没有修改pop2。在chang()中,指针被声明为 consint *,因此不能用来修改指向的int。指针 pc删除了 const特征,因此可用来修改指向的值,但仅当指向的值不是 const 时才可行。因此,pc可用于修改pop1,但不能用于修改pop2。staticcast运算符的语法与其他类型转换运算符相同:

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 来进行向下转换是合法的。同理,由于无需进行类型转换,枚举值就可以被转换为整型,所以可以用staticcast 将整型转换为枚举值。同样,可以使用 static_cast 将 double 转换为 int、将 foat 转换为 long 以及其他各种数值转换。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

通常,这样的转换适用于依赖于实现的底层编程技术,是不可移植的。例如,不同系统在存储多字节整型时,可能以不同的顺序存储其中的字节。
然而,reinterpretecast 运算符并不支持所有的类型转换。例如,可以将指针类型转换为足以存储指针表示的整型,但不能将指针转换为更小的整型或浮点型。另一个限制是,不能将函数指针转换为数据指针,反之亦然。
在 C++中,普通类型转换也受到限制。基本上,可以执行其他类型转换可执行的操作,加上一些组合如 static cast 或 reinterpret_cast后跟const_cast,但不能执行其他转换。因此,下面的类型转换在C语言中是允许的,但在C++中通常不允许,因为对于大多数C++实现,char 类型都太小,不能存储指针:

char ch=char(&d);//type cast#2-convert address to a char

这些限制是合理的,如果您觉得这种限制难以忍受,可以使用C语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值