显式类型转换函数

显式类型转换函数

 一、C 风格(C-style)强制转型如下:

(T) expression // cast expression to be of type T

函数风格(Function-style)强制转型使用这样的语法:
T(expression) // cast expression to be of type T

这两种形式之间没有本质上的不同,它纯粹就是一个把括号放在哪的问题。我把这两种形式称为旧风格(old-style)的强制转型

 

二、C++ style

旧风格的强制转型依然合法,但是新的形式更可取。首先,在代码中它们更容易识别(无论是人还是像 grep 这样的工具都是如此),这样就简化了在代码中寻找类型系统被破坏的地方的过程。第二,更精确地指定每一个强制转型的目的,使得编译器诊断使用错误成为可能。例如,如果你试图使用一个 const_cast 以外的新风格强制转型来消除常量性,你的代码将无法编译。

 

2.1 四个函数概述

C++的四种强制转型形式:
dynamic_cast:
动态类型转换  
static_cast:
静态类型转换
 
reinterpret_cast:
重新解释类型转换
 
const_cast:
常量类型转换  

 

static_cast

用法:static_cast < type > ( expression )
该运算符把expression转换为type类型,但没有运行时类型检查来保证转换的安全性。

一般是普通数据类型(int m=static_cast(3.14));在相关的指针类型或对象之间进行类型转换,在转换时编译器会通过构造函数或转换类型函数转换关系。

static_cast 可以被用于强制隐型转换(例如,non-const 对象转型为 const 对象,int 转型为 double,等等),它还可以用于很多这样的转换的反向转换(例如,void* 指针转型为有类型指针,基类指针转型为派生类指针),但是它不能将一个 const 对象转型为 non-const 对象(只有 const_cast 能做到),它最接近于C-style的转换。

 

它主要有如下几种用法:
用于类层次结构中基类和子类之间指针或引用的转换。
  进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
  进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。

class B { ... };   

class D : public B { ... };   

void f(B* pb, D* pd)   

{   

   D* pd2 = static_cast(pb);        // 不安全, pb可能只是B的指针   

   B* pb2 = static_cast(pd);        // 安全的   

}
用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
把空指针转换成目标类型的空指针。
把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expressionconstvolitale、或者__unaligned属性。

 

static_cast允许执行任意的隐式转换和相反转换动作。(即使它是不允许隐式的)
应用到类的指针上,意思是说它允许子类类型的指针转换为父类类型的指针(这是一个有效的隐式转换),同时,也能够执行相反动作:转换父类为它的子类。
在这例子里,被转换的父类没有被检查是否与目的类型相一致。
class Base {};
class Derived : public Base {};

Base *a    = new Base;
Derived *b = static_cast(a);
'static_cast'
除了操作类型指针,也能用于执行类型定义的显式的转换,以及基础类型之间的标准转换,在可以适用使用标准转换运算符的地方都可以适用static_cast运算符。

double d = 3.14159265;
int    i = static_cast(d);

int i=0;

double d = static_cast(i);

int j = static_cast(d);

 

还有:
class A
{
 protected:
    int m_x;
    char *m_username;
 public :
    A(int x) { m_x=x; }
    A(char *username)

 {
        m_username=new char[strlen(username)+1];
        strcpy(m_username, username);    
    }
   operater int () {  return m_x; }
   operator char *() const  { return m_username; }
}
A a(2);
int x=static_cast(a);
char *p=static_cast(a);
注意:这些static_cast运算符能够正常使用的原因只有一个:类A支持运算符int, const char *overload.否则就和使用标准转换运算符一样是无用的。一般来说,static_cast很少用于指针转换。例如

    int *px;
    double y=2.2;
    px=static_cast(&y);  //syntax error, can not convert double * to int *
//
可以这样理解,static_cast一般用于不同类型的数据的转换,而不能用于转换指针。而reinterpret_cast正好相反,其只能负责不同类型的指针转换。

 

dynamic_cast

一般用在父类和子类指针或引用的互相转化,如果启动了支持运行进类型信息RTTI)可以有助于判断在运行时所指向的对象的确切类型。注:vc++默认式禁止RTTI信息的,若开启,需在工程-》设置,在 c++选项中,选c++语言,勾上“允许运行时类型信息RTTI".

用法:dynamic_cast < type-id > ( expression )

该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。

dynamic_cast 主要用于执行安全的向下转型(safe downcasting,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。在类层次间进行上行转换时,dynamic_caststatic_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

class B{
public:
    int m_iNum;
    virtual void foo();

};

class D:public B{
public:
    char *m_szName[100]

      void print() { cout << "D:print()" << endl; };

};

void func(B *pb){
D *pd1 = static_cast(pb);
D *pd2 = dynamic_cast(pb);

  pd2->print();

  pd2->m_szName[0]=’a’; // error

  pd1->m_szName[0]=’a’; //right;

}

在上面的代码段中,如果pb指向一个D类型的对象,pd1pd2是一样的,并且对这两个指针执行D类型的任何操作都是安全的;
但是,如果pb指向的是一个B类型的对象,那么pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的(如访问m_szName),pd2将是一个空指针(
检测在运行时进行,如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL表达式dynamic_cast(a) a值转换为类型为T的对象指针。dynamic_cast是一种试探性映射,如果类型T不是a的某个基类型,该操作将返回一个空指针。为空了还能执行print(),解释:C++对类成员函数只有一份拷贝,编译器只要知道了是哪个类就可以调用其成员函数,但是每个类对象的成员变量是分开存储的,所以如果调用了成员变量的话应该就会报错了)
另外要注意:B要有虚函数,否则会编译出错;static_cast则没有这个限制。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表,没有定义虚函数的类是没有虚函数表的。

'dynamic_cast'只用于对象的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程)。static_cast通常可用于类层次的静态导航,无映射变换,窄化变换(会丢失信息)等等,static_cast的应用要广一些,但如前所提到的,在类层次导航变换中我们应该使用前者,因为后者static_cast可能意味着冒险(比如变换时类似于强制转换一样丢失信息)。在某些情况下较dynamic_cast.

另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。
class A{
 public:
    int m_iNum;
    virtual void f(){}

};
class B:public A{ };
class D:public A{ };

B *pb = new B;
pb->m_iNum = 100;
D *pd1 = static_cast(pb); //compile error
D *pd2 = dynamic_cast(pb); //pd2 is NULL
delete pb;

使用static_cast进行转换是不被允许的,将在编译时出错;而使用 dynamic_cast的转换则是允许的,结果是空指针。

reinterpret_cast

很像c的一般类型转换操作,是最危险的,只要编译通过就行,使用不当的话很有可能导致RUN-TIME大灾难是强制转换,而不论是否提供了相应构造函数或转换类型数,因此,在转换时其内存格式并不变化,例如,当对double转换成int后,通过cout输出时,输出的仍然是double类型,其主要目的是:将一个指针转换成其它类型的指针。这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。
    reinterpret_cast
是特意用于底层的强制转型,导致实现依赖(implementation-dependent)(就是说,不可移植)的结果,例如,将一个指针转型为一个整数。这样的强制转型在底层代码以外应该极为罕见。

class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast(a);
'reinterpret_cast'
就像传统的类型转换一样对待所有指针的类型转换。


const_cast

是把cosntvolatile属性去掉,const_cast 一般用于强制消除对象的常量性。去除常量变量的常量属性,或反之将非常量的指针变量转换成常指针变量。

   const int x=12;
    int *px=x; //syntax error, int pointer can not point to const int
可以改为:
    const int x=12;
    int *px=const_cast(&x);
    *px=20;//ok 
//x
值没有变化!!!!也不能x = 5;


又例如:
class Account
{
   int balance;
 public:
    Account(int b) { balance=b; }
    void operater +=(int newbalance) { balance+=newbalance; }
 }
const Account a(9000);
Account *pa=&a;//syntax error!
*pa+=1000;//syntax error!
可以改为:
const Account a(9000);
Account *pa=const_cast(&a);
*pa+=1000;
这样的话 const对象a balance就变为10000了!!

总的来说,const_cast的主要作用之一是去掉const保护。因此少用为好。

你可能感兴趣的:(C++,class,编译器,存储,c,null,语言)