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

c++命名类型转换

2016-06-01 21:16 225 查看

C++的4种命名类型转换

格式:cast-name<type>(expression);
其中type是待转换的目标类型,expression是被转换的值;若type是一个引用,则转换后的结果是一个左值。
cast-name是以下4种中的一种:
static_cast, dynamic_cast,const_cast,reinterpret_cast
其中dynamic_cast支持运行时类型识别,以下只介绍前3种。

static_cast

除了涉及low-level const,任何其他定义良好的类型转换都可以使用static_cast。例如,可以将int型操作数转换成double以达到在在语句中使用浮点型进行除法操作的目的。

static_cast的应用场景:
1.当一个较大的数据类型被赋值为一个较小的数据类型。使用该转换后,编译器会关闭警告信息(潜在的精度丢失)

int	i, j;
double d = static_cast<double>(j) / i;


2.编译器不会自动转换时
例如,使用static_cast获得一个void* 类型的指针所指向地址的值

void* p = &d;	//ok:任何非const类型的对象可以用void* 存储
double *dp = static_cast<double*>(p);	//ok:转换void* 回到原始指针类型


const_cast

cosnt_cast只改变操作数的low-level const
const char* pc;
char* p = const_cast<char*>(pc);//ok:但是写p操作未定义

若原类型为非const,使用该转换获得写权限是合法的;否则未定义
const_cast通常只被用来改变一个表达式的常量属性。试图通过其他的转转(非const_cast)改变表达式的常量属性会在编译器出错。同样地,不能用const_cast改变表达式的类型
const char* cp;
char* q = static_cast<char*>(cp);
static_cast<string>(cp);// ok
const_cast<string>(cp);//error:const_cast只改变常量属性

const_cast的应用场景:在重载函数中最常用到

reinterpret_cast

reinterpret_cast 通常对操作数的位模式(bit pattern)重新解读
例如:
int* ip;
char* pc = reinterpret_cast<char*>(ip);

pc所指向的实际对象为int类型,而不是char。任何假使pc所指向的类型是一个char类型的使用都会在运行时出错
例如:
string str(pc);</span></span>
注意:使用pc初始化str是危险的。问题在于类型改变了,编译器假设pc是char*类型,然后使用pc初始化string类型,这对编译器来说是合法的,所以此时编译器不会给出任何警告和报错,然而实际上pc是一个int*。此时初始化是无意义的甚或者比较糟糕。追踪这种问题导致的结果非常困难,尤其是当ip到pc的转换发生在和用pc初始化str不同的文件。
警告:
reinterpret_cast是依赖于机器的。想要安全地使用reinterpret_cast需要全面理解以及知道编译器实现它的细节。

dynamic_cast

Run-time identification(RTTI)可以通过两个操作符实现:
1.typeid,返回指定表达式的类型
2.dynamic_cast,安全地将指向基类的指针或引用转换为指向子类的指针或引用
当需要用指向基类的指针或引用来操作子类时,可以选择虚函数实现。当该操作不能定义为虚函数时,可以使用这两个操作符中的一个来实现。当然,使用操作符来实现更以出错:程序员必须知道要转换的类型以及确保转换成功。
警告:
RTTI应当小心使用。尽量使用虚函数而不是直接通过操作符来直接管理类型。

dynamic_cast有以下3中形式:
1.dynamic_cast<type*>(e)
2.dynamic_cast<type&>(e)
3.dynamic_cast<type&&>(e)
其中type必须是class类型并且通常是有虚函数的类
1中e必须为合法的指针,2中e必须为左值,3中e不能为左值,e可以从目标类型公有继承而来,可以是目标类型的公有基类,或者和目标类型相同。以上情形下转换才会成功;否则,转换回失败。若dynamic_cast转换成某个指针类型失败,结果为0,;若转换为某个引用类型失败,则会抛出一个bad_cast。

pointer_type dynamic_casts
例如:Base作为基类并且至少有一个虚函数,Derived公有继承自Base。bp指向Base,在运行时,可以将bp转换为指向Derived的指针
if(Derived* dp = dynamic_cast<Derived*>(bp))//在条件语句中初始化bp确保bp在if语句外部不可用;如果转换失败,dp也不可访问
{
//use the Derived object to which dp points
}else{	//bp points at a Base object
//use the Base object to which bp points
}
注意:
可以使用dynamic_cast对空指针进行转换,转换结果为要转换类型的空指针

reference_type dynamic_casts

由于引用不能为空,所以当转换为引用失败时会抛bad_cast异常(在typeinfo库中定义)
可以使用引用并改写之前的例子
void f(const Base &b)
{
try{
const Derived &d = dynamic_cast<const Derived&>(b);
}catch (bad_cast) {
//handle the fact that the cast failed
}
}


延伸:Old-Style Casts

在早期版本的C++中,显式转换有以下两种形式:

type (expr);	//函数风格的转换
(type) expr; 	//C语言风格的转换


建议:

转换涉及正常的类型检查。因此强烈建议程序员避免转换。此建议尤其对reinterpret_cast适用。这种转换总是有风险的。const_cast在重载函数中很有用,而其他的用法则是一个程序设计的缺陷。关于其他的类型转换,如static_cast和dynamic_cast,不应该频繁使用。每次在写一个转换之前,需要考虑清楚是否可以通过一个不同的方法来达到同样的目的。如果转换在所难免,可以通过限定转换值使用的范围并且记录关于类型的所有假设来使错误发生的概率减小。

依赖于所涉及的类型,旧风格的转换可以实现和const_cast, static_cast, reinterpret_cast同样的效果。当用static_cast或者const_cast合法的时,用旧风格也可以完成和相应的命名转换同样的转换。如果这两种转换都不合法,则旧风格的转换等同于reinterpret_cast. 例如:
char* pc = (char*) ip;	//ip是一个int*

和使用reinterpret_cast有同样的效果。
警告:
旧风格的转换相比命名转换而言不明显。因为很容易被忽略,所以追踪一个不合法的转换非常困难。

Reference:C++ Primer, 5th edition
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: