C++标准类型转换

来源:互联网 发布:西岐网络 编辑:程序博客网 时间:2024/05/20 17:07
class   Base_1
{
public:
    void  function1()
    {
           cout<<" function1   of   Base_1"<<endl;
    }
    virtual void func()
    {

    }
};

class   Base_2
{
public:

    void function2()
    {
        cout<<"  function2    of   Base_2"<<endl;
    }
};

class   Base_3:public Base_1, public  Base_2
{
public:

    void  function1()
    {
        cout<<" function1    of    Base_3"<<endl;
    }

};


int main()
{
    Base_3   dst;

    Base_1   src;

    

    一、static_cast   用法:static_cast < type-id > ( expression ) :将expression转换为type-id,但没有运行时类型检查来保证转换的安全性
                 四种转换类型中唯一一个可以用于非指针、非引用类型的转换。


         //用法:1.用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换

                     //上行转换(把派生类的指针或引用转换成基类表示是安全的:
                             
                                   Base_1  src1 = static_cast<Base_1>(dst);
                                          

                     //下行转换(把基类指针或引用转换成派生类表示时,由于没动态类型检查,所以是不安全的
                                 // Base_3   dst1=static_cast<Base_3>(src);//报错: 不存在用户定义的从 "Base_1" 到 "Base_3" 的适当转换    


                                   Base_3   *dst1=static_cast<Base_3*>(&src);//改成指针就可以。那么问题来了在上行转化的时候不是指针可以,下行转换就不行呢?
                                                                             //解释:
                                                 
              
    
                //2..普通类型转换
                     int i=100;
                     void *p =(void *)i;

                    // int j=static_cast<int>(p)//报错:转换类型无效,意图将 void* 转换为  int
                      int *j=static_cast<int*>(p);
                      
                //3.把空指针转换成目标类型的空指针。
                //4.把任何类型的表达式转换成void类型。



    //二、dynamic_cast    用法:dynamic_cast < type-id > ( expression ) :将expression转换为type-id,Type-id必须是类的指针、类的引用或者void*。
                      //支持子类指针到父类指针的转换,并根据实际情况调整指针的值,和 static_cast不同,反过来就不支持,会导致编译错误
                      //要求:第一、必须用于类与子类之间的转换;

                             //第二、必须用于指针或引用类型的转换;()
                                      
                                             
                             //第三、下行转换时要求基类必须有虚函数(基类中包含至少一个虚函数)。

                     Base_1  src_1;
                     Base_3  *dst2 = dynamic_cast<Base_3*>(&src_1);//如果Base_1中没有虚函数则报错: 运行时 dynamic_cast 的操作数必须包含多态类类型

                         dst2->function2();
     //将父类经过dynamic_cast转成子类的指针竟然是空指针!这正是dynamic_cast提升安全性的功能,dynamic_cast可以识别出不安全的下行转换,但并不抛出异常,而是将转换的结果设置成null(空指针)。

    
                                        
        getchar();

    return  0;

}


//以下为转载

3. const_cast<type-id>(expression)

编译器在编译期处理
去掉类型中的常量,除了const 或不稳定的变址数,type-id和expression必须是相同的类型。
表达式const_cast<type-id>(expression)被用于从一个类中去除以下这些属性:const, volatile, 和 __unaligned。

[cpp] view plaincopy
  1. class A { ... };    
  2. void f()    
  3. {    
  4.     const A *pa = new A;     <span style="color:#009900;">// const对象 </span>   
  5.     A *pb;                   <span style="color:#009900;">// 非const对象</span>    
  6.     pb = pa;                 <span style="color:#009900;">// 出错,不能将const对象指针赋值给非const对象</span>    
  7.     pb = const_cast<A*>(pa); <span style="color:#009900;">// 现在OK了</span>    
  8.    ...    
  9. }    

对于本身定义时为const的类型,即使你去掉const性,在你操作这片内容时候也要小心,只能r不能w操作,否则还是会出错:

[cpp] view plaincopy
  1. const char* p = "123";     
  2. char* c = const_cast<char*>(p);     
  3. c[0] = 1;   <span style="color:#009900;">//表面上通过编译去掉了const性,但是操作其地址时系统依然不允许这么做。</span>  

const_cast操作不能在不同的种类间转换。相反,它仅仅把一个它作用的表达式转换成常量。它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。尽量不要使用const_cast,如果发现调用自己的函数,竟然使用了const_cast,那就赶紧打住,重新考虑一下设计吧。

去除“指针”或“引用”的const、volatile、_unaligned性。很多人都认为用这个运算符就可以让const这么“固若金汤”的东西“形同虚设”,实则不然。本质上它能做到也就是仅仅为你剥去一层虚假的外壳。如果“被指向”或“被引用”的东西本身就是const的,那么任凭你费多大力气都是徒劳的。一般它都是在这样的一套逻辑中:

[cpp] view plaincopy
  1. int a=34;  
  2. const int * pcint=&a;  
  3. int *pint=const_cast<int*>(pcint);  
  4. *pint=0;  

这样就修改了本来是const的指针(该指针要求不能修改它指向的东东,这里如果改为const int a=34;那么虽然编译依然能通过,运行依然OK,但是实际上当你用*pint来修改时,你会得到修改后的值为:a依然为34;而*pint确实为0了,但有趣的是此时pint=&a依然成立,虽然pint指向a,但是取出它的值却不等于a了。至此,希望大家今后不要再误用const_cast了。

4. reinterpret_cast<type-id>(expression)--重解释转换

编译器在编译期处理
任何指针都可以转换成其它类型的指针,type-id必须是一个指针、引用、算术类型、指向函数的指针或指向一个类成员的指针。
表达式reinterpret_cast<type-id>(a)能够用于诸如char* 到 int*,或者One_class* 到 Unrelated_class*等类似这样的转换,因此可能是不安全的。用于对指针的重新包装,也就是指针类别之间的转化。除此之外还可以用于指针类型与unsigned int类型之间的转化。

[cpp] view plaincopy
  1. class A { ... };    
  2. class B { ... };    
  3. void f()    
  4. {    
  5.     A* pa = new A;    
  6.     void* pv = reinterpret_cast<B*>(pa);    
  7.     // pv 现在指向了一个类型为B的对象,这可能是不安全的    
  8.     ...    
  9. }   

使用reinterpret_cast 的场合不多,仅在非常必要的情形下,其他类型的强制转换不能满足要求时才使用。

这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现,举个例子:

class A {};

class B {};

A * a = new A;

B * b = reinterpret_cast<B*>(a);// 正确

更厉害的是,reinterpret_cast可以把整型数转换成地址(指针),这种转换在系统底层的操作,有极强的平台依赖性,移植性差。它同样要求new_type是指针或引用,下面的例子是通不过编译的。

double a = 2000.3;

short b;

b = reinterpret_cast<short> (a); // 编译错误

类型转换符相互比较

1. static_cast vs reinterpret_cast

     reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的(这句话是C++编程思想中的原话)。
     static_cast 和 reinterpret_cast 操作符修改了操作数类型,它们不是互逆的。
     static_cast 在编译时使用类型信息执行转换,在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的。
     另一方面,reinterpret_cast是C++里的强制类型转换符,操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。
例子如下:

[cpp] view plaincopy
  1. int n=9;     
  2. double d=static_cast < double > (n);  

上面的例子中,我们将一个变量从 int 转换到 double。这些类型的二进制表达式是不同的。 要将整数 9 转换到双精度整数9,static_cast 需要正确地为双精度整数 d 补足比特位。其结果为 9.0。

而reinterpret_cast 的行为却不同:

[cpp] view plaincopy
  1.   
[cpp] view plaincopy
  1. int n=9;     
  2. double d=reinterpret_cast<double & > (n);  

这次, 结果有所不同。在进行计算以后, d 包含无用值。这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d,没有进行必要的分析。因此,你需要谨慎使reinterpret_cast。
reinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。
例如,假设你有一个函数指针数组:
[cpp] view plaincopy
  1. typedefvoid(*FuncPtr)();// FuncPtr is一个指向函数的指针,该函数没有参数,返回值类型为void    
  2. FuncPtrfuncPtrArray[10];// funcPtrArray是一个能容纳10个FuncPtrs指针的数组    

你不能不经过类型转换而直接去做,因为doSomething函数对于funcPtrArray数组来说有一个错误的类型。在FuncPtrArray数组里的函数返回值是void类型,而doSomething函数返回值是int类型。

funcPtrArray[0] = &doSomething;// 错误!类型不匹配 

reinterpret_cast可以让你迫使编译器以你的方法去看待它们:

funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);

转换函数指针的代码是不可移植的(C++不保证所有的函数指针都被用一样的方法表示),在一些情况下这样的转换会产生不正确的结果。

2. dynamic_cast vs static_cast

class B { ... };

class D : public B { ... };

void f(B* pb)
{

    D* pd1 = dynamic_cast<D*>(pb);

    D* pd2 = static_cast<D*>(pb);
}
    如果pb确实是指向D类型对象,则pd1和pd2将拥有同样的值。即使pd为0,它们的值也相同。如果pb执行B类型对象而不是D类型,则dynamic_cast返回0.可是static_cast依赖编程者安全断言--pb指向D类型对象并简单地返回给定的D对象指针。

    即dynamic_cast可用于继承体系中的向下转型,即将基类指针转换为派生类指针,比static_cast更严格更安全。dynamic_cast在执行效率上比static_cast要差一些,但static_cast在更宽上范围内可以完成映射,这种不加限制的映射伴随着不安全性。static_cast覆盖的变换类型除类层次的静态导航以外,还包括无映射变换、窄化变换(这种变换会导致对象切片,丢失信息)、用VOID*的强制变换、隐式类型变换等.
0 0