C++类型转换

1.引言

       C++的强制类型转化用于不同的情况和原因,比C进步的是C++将这些情况细分并用不同的强制类型转换符号来表示。这样程序就比C更容易解析。

       命名的强制类型转换符号的一般形式如下:

cast-name<type>(expression);

其中cast-name为static_cast、dynamic_cast、const_cast、reinterpret_cast之一,type为

换的目标类型,而expression则是被强制转换的值。

2.static_cast

       编译器隐式执行的任何类型转换都可以由static_cast显示完成,也就是说一般的类型转换都是使用static_cast比较好。static_cast基本上拥有与C旧式转换相同的威力与意义,以及相同的限制。例如你不能够利用static_cast将一个struct转型为int,或者将一个double转型为pointer。

3.const_cast

const_cast就是用来转换表达式的const性质。例如: constchar *pc_str; const_cast<char*>(pc_str); 类似地,除了添加或者删除const特性,用const_cast符来执行其他任何类型转换,都会引起编译错误。

4.reinterpret_cast

reinterpret_cast通常为操作数的位模式提供较低层次的重新解释。reinterpret_cast本质上依赖于机器。为了安全使用reinterpret_cast,要求程序员完全理解所涉及的数据类型,以及编译器实现强制类型转换的细节。由于reinterpret_cast与编译平台相关,所以不具备可移植性。至今我都没有讲过reinterpret_cast的例子程序。用的很少也不建议使用。

5.dynamic_cast

5.1type_info

       对于这个类型转化是与C++的RIIT特性相关的。

       首先解释一下tpye_info结构,C++中各个类型(无论是内置类型还是自定义类型)的信息都由各自的type_info来描述。这里从VC++的typeinfo.h中找到VC++版本下的type_info定义:

class type_info {
public:
    virtual~type_info();
    intoperator==(const type_info& rhs) const;
    intoperator!=(const type_info& rhs) const;
    intbefore(const type_info& rhs) const;
    constchar* name() const;  //传回原始名称
    constchar* raw_name() const;   //传回编码后名称
private:
   void *_m_data;
   char _m_d_name[1];
   type_info(const type_info& rhs);
   type_info& operator=(const type_info& rhs);
};

       以下的一段程序测试了tpyeid(取得类型的type_info结构)的功能:

#include<iostream>
#include<typeinfo>
using namespace std;
class B{};
class D:public B{};
int main()
{
       //测试组1
       intvInt=10;
       intarr[2]={10,20};
       int*p=&vInt;
       int**p2p=&p;
       int*parr[2]={&vInt,&vInt};
       int(*p2arr)[2]=&arr;
       //测试组2
       B*pb=new B;
       D*pd=new D;
       B*pbd=new D;
       //测试组1结果
       cout<<"测试组1结果"<<endl;
       cout<<"Declaration [intvInt=10]type=="<<typeid(vInt).name()<<endl;
       cout<<"Declaration [intarr[2]={10,20}]type=="<<typeid(arr).name()<<endl;
       cout<<"Declaration [int*p=&vInt]type=="<<typeid(p).name()<<endl;
       cout<<"Declaration [int**p2p=&p]type=="<<typeid(p2p).name()<<endl;
       cout<<"Declaration [int(*p2arr)[2]=&arr]type=="<<typeid(p2arr).name()<<endl;
       //测试组2结果
       cout<<"测试组2结果"<<endl;
       cout<<"pb's type name =="<<typeid(pb).name()<<endl;
       cout<<"pd's type name =="<<typeid(pd).name()<<endl;
       cout<<"pbd's type name =="<<typeid(pbd).name()<<endl;
       //测试编码后名称
       cout<<"测试编码后名称"<<endl;
       cout<<"pb's type rawname =="<<typeid(pb).raw_name()<<endl;
       cout<<"pd's type rawname=="<<typeid(pd).raw_name()<<endl;
       cout<<"pbd's type rawname=="<<typeid(pbd).raw_name()<<endl;
       return0;
}

       程序的输出结果为:

C++类型转换_第1张图片

       这个程序要注意的一点是:

cout <<"Declaration [intarr[2]={10,20}]type=="<<typeid(arr).name()<<endl;

明明是一个数组确显示为一个指针,因为typeid是函数操作。所以数组名退化为指针了,个人认为在这一点上typeid的设计尚有欠缺,至少在VC++环境下是如此。

5.2dynamic_cast功能

       dynamic_cast用来执行继承体系中“安全的向下转型或跨系转型动作”。也就是说你可以利用dynamic_cast将“(类型为)指向基类对象的指针”转型为“(类型为)指向派生类对象的指针”,并得知转型是否成功。如果转型失败会以一个null指针(当转型对象是指针)或一个exception(当转型对象是引用)表现出来。

#include<iostream>
#include<typeinfo>
using namespace std;
class B
{
public:
       B(){}
       virtualprint(){cout<<"B"<<endl;}
};
class D:public B
{
public:
       D(){}
       virtualprint(){cout<<"D"<<endl;}
};
void Print(D* p)
{
       p->print();
}
void PPrint(D& d)
{
       d.print();
}
int main()
{
       Bb;
       B&rb=b;
       B*pb=new B;
       D*pd=new D;
       B*pbd=new D;
       Print(dynamic_cast<D*>(pb));
       PPrint(dynamic_cast<D&>(rb));
       return0;
}

       这个程序是异常的。

       另外值得注意的是:dynamic_cast只能用于有虚函数的继承体系中!!!!!!!!

6.对cast的点评

       避免使用强制类型转换,强制类型转换关闭或者挂起了正常的类型检查。强烈建议程序员避免使用强制类型转换,不依赖强制类型转换也能写出很好的C++程序。这个建议在如何看待reinterpret_cast的使用时非常重要。此类强制类型转换总是非常危险的。相似地,使用const_cast也总是预示着设计缺陷。设计合理的系统应不需要使用强制类型转换抛弃const特性。其他的强制类型转换,如static_cast和dynamic_cast,各有个的用途,但都不应当频繁使用。每次使用强制转换前,程序员应该仔细考虑是否还有其他不同的方法可以达到同一目的。如果非强制转换不可,则应限制强制转换值的作用域,并且记录所有假定涉及的类型,这样能减少错误发生的机会。


你可能感兴趣的:(cast)