网络推荐



本广告位招租!

推荐给好友 上一篇 | 下一篇

[C++对象模型]类型转化

i4S ]1c6C'f ST8O'`一 typeid与dynamic_castBSD爱好者乐园:}_|2n h6D@

BSD爱好者乐园+P2@;m? D.T

1)RTTI, Runtime Type Identification (RTTI) or Run-time type information (RTTI),表示在运行时动态决定变量的类型,来调用正确的虚函数。 RTTI在VS2008中默认为关闭,可以通过修改编译选项Enable Run-Time Type Info 为 Yes,来启用RTTI,只有当启动RTTI时,用来RTTI功能的typeid和dynamic_cast才能正常工作。

7\1d,GO y[W4~

&q,KG*f [ nw2)type_info,用来描述类型信息。type_info存储了它所描述的类型的名字。RTTI就是使用type_info来实现的。type_info的定义如下:

$g\}kVx7@8[
CodeBSD爱好者乐园5a!n%Nr`
class type_info {BSD爱好者乐园"{g w/XN
public:BSD爱好者乐园%S,RHz|7ht
  
virtual ~type_info();BSD爱好者乐园4dTP)P ]Rh
  
bool operator== (const type_info& rhs) const;BSD爱好者乐园K,F,dMMF8xeN
  
bool operator!= (const type_info& rhs) const;
']fn6VRc]  
bool before (const type_info& rhs) const;
]S/tHE  
const char* name() const;BSD爱好者乐园;f!u H4i eg&F!c
private:
v.UVjZ,Ze  type_info (
const type_info& rhs);BSD爱好者乐园km8zV1d*i)At-l
  type_info
& operator= (const type_info& rhs);BSD爱好者乐园/r%@9Uzb7_
};BSD爱好者乐园 F/J%@?.bs
BSD爱好者乐园g)Z r6ZbMM'[Y

 BSD爱好者乐园9D%rm `'?:A!u J

0I9]+g2W0s问题:RTTI怎么实现那?对象,type_info,虚函数怎么关联那?《深入C++对象模型》中说在虚函数表的开始存储了类型信息,但是实际的VS2008中好像并没有此信息,请高人指点哦!
fos Sk2c e1O
BSD爱好者乐园fG&j.c'Fw

J$P7I)s @A!Z\3)typeid,在运行时获得对象的类型,typeid()返回的是const type_info&,而 type_info包含了对象真实类型的名字。typeid能被用来获取一个引用对象或指针指向的对象的运行时的真实类型。当然如果对象为null或编译时没有使用/GR的话,typeid的会抛出异常bad_typeid exception或__non_rtti_object。实例代码:BSD爱好者乐园e#^0J X2vmA+O y g%D

Code
~e$J_{Nclass Base BSD爱好者乐园/L9A+CZ.E E mMCr
{
!yL3v P'uqE
public:BSD爱好者乐园'`4d?!HE9W |Lw@
    
virtual void f(){ }
|N-]"[G$M1n};BSD爱好者乐园Oj?DSW2T~U
 
5nLSwIHj
class Derived : public Base 
t4da-BeBSD爱好者乐园A!j^'d&m"?@e
public:BSD爱好者乐园^'Cnlqi
    
void f2() {}
)kE)OY(|O Ptkx&l,N8H}; BSD爱好者乐园 e,~|C$@w
BSD爱好者乐园f^Y%`.WH
void main ()BSD爱好者乐园_T9r7Ys6nJ
{BSD爱好者乐园!q%Xi\[F Y
    Base 
*pB = new Derived();
ok[ Gys\2LkE    
const type_info& t = typeid(*pB);cout <<t.name() << endl;
t7]R ~V    delete pB;
n OL(W i
9["}0I4r/F-?    Derived d;
&O~qB+mL$V3B    Base
& b = d;
3Q0Z J2M ] ht y    cout 
<< typeid(b).name() << endl;
K Q pD)^.g-|}
BSD爱好者乐园 Y;J&bWX@'r NR1q)\

 BSD爱好者乐园YO_*E_F7Be

[t2o7QN|+~运行结果:BSD爱好者乐园WbE!JrII] G

Ab,f*f)@,EqD%l EBSD爱好者乐园y9p:g4m1L+d

-BY%pdb/`*@8k 

u%Jn hz|T'W!rJ%B
    BSD爱好者乐园P(bf rD2Oc

    4)dynamic_cast,用来运行时的类型转化,需要/GR来正确运行。BSD爱好者乐园4q @ lb#f%v uF
    适用:BSD爱好者乐园BsoG)R
    第一,用于所有的父子和兄弟间指针和引用的转化,有类型安全检查;
     BSD爱好者乐园6ZhE A)t%Y9P2o;n
    第二,对指针类型,如果不成功,返回NULL,对引用类型,如果不成功,则抛出异常;
     BSD爱好者乐园 me5LO3ImjJ
    第三,类型必须要有虚函数,且打开/GR编译选项,否则不能使用dynamic_cast。BSD爱好者乐园g h sm0T;G~j Zv
    实例代码:

    6zV'~T%l!p.V7n{/X)N6G
    Code
    ls(j(m nclass AA 
    f9V,a XZ&k+r{BSD爱好者乐园PYz!fk
    public:
    Wvk.}0@-plA G6j    
    virtual void do_sth(){ std::cout<<"AA\n"; }BSD爱好者乐园 jr&P,{ tRb9XP
    };BSD爱好者乐园,F.Y;UG[
    class BB BSD爱好者乐园"O)N4a'q'LO)M
    {
    A9c-k(\x} R
    public:
    4h'v1bb4y"K?    
    virtual void do_sth(){ std::cout<<"BB\n"; }
    v#u2}bvmN};BSD爱好者乐园f?)r#d{0A5Y
    class CC : public AA, public BB
    ;[(G5D'_5S d M{
    {)Fi%U4p
    public:
    i_Vx,`5yH Xdb|    
    virtual void do_sth(){ std::cout<<"CC\n"; } 
    $R&[O4@9qu&e2?(O};
    (b9mT8x@B"^
    h_FtM/u
    void DynamicCastTest()
    *P#r3B|*bq1|o g!xv{BSD爱好者乐园Dq,SAE:{"BH-V|(f
        AA 
    *pA = new CC;BSD爱好者乐园)?i)B7?Y\9KH
        BB 
    *pB = dynamic_cast<BB*>(pA);BSD爱好者乐园9K's [2f(i.M
        
    if(pB != NULL)BSD爱好者乐园H7D#CAp]+Q
            cout 
    << "cast successful!" << endl;
    #C$GiFiR4bP7Unf    CC 
    *pC = dynamic_cast<CC*>(pA);BSD爱好者乐园4Y4m P#vN0I1Tdrtkx
        
    if(pC != NULL)BSD爱好者乐园GL(I+gi?
         cout 
    << "cast successful!" << endl;
    N*FtgIa$W}
    BSD爱好者乐园N5dn3k4q y3TJ

     

    #Y7X+` L e8T&PBSD爱好者乐园H+{"B QNuuqFi

    二 其他cast

    T!Y#` SJ^.] F

    @/c;P&CP|#` d%jR1)隐式转化,不需要任何操作符,转化被自动执行,当一个值被赋值到它所兼容的类型时。
    9m*n+xtq7o|适用:
    ew| {?z6Y第一,内置基本类型的兼容转化;BSD爱好者乐园 F` l%I _'O
    第二, 子类指针,引用向父类的转化;
    BSD爱好者乐园(I:R(h,g G

    BSD爱好者乐园T?i-p9a+mjH

    实例:

    B/s6vNI$G1h2N
    Code
    }WWU oSJclass A
    :z Ys~4h.Y{BSD爱好者乐园e7UEd"E0dq
    public:BSD爱好者乐园eA \5T-C
        
    virtual ~A(){}
    A*z2LhG [-u};BSD爱好者乐园s(u!_ H9f|,}/M'pU
    class B : public A
    m.l]5De{}X{BSD爱好者乐园,f7Ld8e8S9k8?};?a
    };BSD爱好者乐园4CNG:o}U-x
    BSD爱好者乐园2j2d"E.r't
    void ImplicitCast()
    J!Y F'@:r y{BSD爱好者乐园"u;FB/A3~ \ d
        
    short a = 2000;BSD爱好者乐园x/z*O Jp
        
    int b;
    %T?)^~nM%s    b 
    = a;
    q_ o/YVd(t:x9B c1{BSD爱好者乐园H4F-RJ[,v&V
        
    double d = 10.05;
    V7ntQ8Q/[;| [    
    int i;BSD爱好者乐园!t8h-AhYzv:^3gZ
        i 
    = d;
    |5C0BZ$Aq _j]v
    "Dh+x8\FC6d    
    int j = 75;
    RW&t+Frm#L,|9c    
    char c;
    7wj*~Vb ^y|Q/} d    c 
    = j;BSD爱好者乐园F,Xm"F(f t*e

    !`'P!M`$uKSo-P3V    A
    * pA = new B();
    D_E_2R.f'mD}
    BSD爱好者乐园8^+K.tb!eo-E k y.O

     

    #f~0vW`u@w3hBSD爱好者乐园c.df)k%PC|Q%w

    2)强制类型转化,即我们常说的C风格的类型转化,基本上可以用于所有的转化,但是没有意义的转化除外,但是父子类,兄弟间的转化没有类型检查可能导致运行是错误。BSD爱好者乐园+xb,@i7w}S
    适用:
    :m&\0R2?4U { `P2d?第一,基本类型转化;BSD爱好者乐园/Axy#N.w9o
    第二,void*到其他指针的转化;
    #R4Gmh;`,e第三,去除const;
    9a"?wT'U0UR#A第五,函数指针的转化;BSD爱好者乐园2Y^hH }k
    第六,父子类转化,但是多重继承和兄弟转化,可能有运行时错误,没有类型检查;
    :B/z,byrZ8i]第七,任何两个类,但是没有实际意义,运行可能出错;BSD爱好者乐园 ]_;?oimB
    第八,不能用于没有意义的转化,严厉禁止,例如,你不能用static_cast象用C风格的类型转换一样把struct转换成int类型,或者把double类型转换成指针类型;BSD爱好者乐园 z;D/P@4O2T
    第九,在C++一般更推荐新加的static_cast,const_cast,dynamic_cast和reinterpret_cast转化方式;

    NE8M.r/k5n5K!|!yBT

    hHOZ"D$C'ef实例:

    "ZGX le,o
    CodeBSD爱好者乐园%u*U9q1mm1L*i6Y}3]
    class CDummy BSD爱好者乐园6f;^8GQ^
    {
    B)W r@$?0b8~
    public:
    .`Ql1Dmb    CDummy(
    float x, float y)BSD爱好者乐园H#xh0? Y(G
        {BSD爱好者乐园c;Q7X`XW#~
            i 
    = x;
    *]#l~ |_        j 
    = y;BSD爱好者乐园 i-b6oDeV)C
        }BSD爱好者乐园(e/Xd |Fm
    private:BSD爱好者乐园(V/U'sl G9y
        
    float i,j;BSD爱好者乐园1G$O@5@}(FBk
    };BSD爱好者乐园 V4F%sqV:J

    Z+_Ef]O5Z)H
    class CAddition 
    xm4k0]{+S0zZ{BSD爱好者乐园1X-S*GJyp?r#X
    public:BSD爱好者乐园~+{W }:il RgH:U#m
        CAddition (
    int a, int b) { x=a; y=b; }BSD爱好者乐园,G o&k/fMt4v5d
        
    int result() { return x+y;}
    M8Fm"m6er
    private:
    ;rk5a#X~8jv,j    
    int x,y;
    7p.K[2x;CP"^e @-x};BSD爱好者乐园8VC D `i:w)Tfv$h$@.H

    I;Y V/FminO
    int Testing()
    :W;eC8},Y]{
    .G u*@ x/\l&C0n+a    std::cout 
    << "Testing" << std::endl;
    c'mb:]8|/s    
    return 10;
    3_!{D_.F.J3VI by}BSD爱好者乐园#BM1Qz k q'E

    J XnSO rY;_@h
    void ExplicitCast()BSD爱好者乐园_3zr nsQ3o/EE'm6b9Q+r
    {BSD爱好者乐园+S-}Uz/D;?i`$l
        
    double r = (double)1 / 3;
    ;NJ0_X eBSD爱好者乐园%zEo4M I Pc#R
        
    int *pi = new int(10);BSD爱好者乐园VF7^#^9Z(F8CjH"C5T
        
    void *pV;BSD爱好者乐园vu;FR dqt4VM1i
        pV 
    = pi;
    :C/t%z yq cn&L|[J    
    int *pj = (int*)pV; // 或 int *pj = int*(pV);
    SS8J/Qe XN9N_

    }#r xwbLbq    
    const int* pa = new int(20);BSD爱好者乐园:Ma!s_9v)}f,f]
        
    int *pb;BSD爱好者乐园]9nzQ1E.qhA
        pb 
    = (int*)pa;
    u%X?)i~-{,n7c S    
    *pb = 30;
    8Xx#H`j wsbHdOa    std::cout 
    << *pa << std::endl;
    :X0b.tsn^S"^BSD爱好者乐园m7Kh)@2ek7I.yQrA
        typedef 
    void (*Fun)();BSD爱好者乐园5d?1r!HtDs*l

    7Y @J7E@%QqO    Fun f 
    = (Fun)Testing;BSD爱好者乐园1h-T"jG*nO\ fwR
        f();
    W C0x;EYg K(Q)OBSD爱好者乐园9{H'v6Zw7\.b+Z
        
    // 多重继承或将兄弟间的转化可能会出错
    jE*]}#_
    Zd0d.U6w,iM$y    
    // 虽然可以正确的编译,但是运行有问题,所以我们不做没有意义的转化BSD爱好者乐园f;z[!X*QI8n
        
    //CDummy d(10,30);
    5k2N!z&X.z q&_,uN@    
    //CAddition * padd;BSD爱好者乐园K,K8m)OLA g
        
    //padd = (CAddition*) &d;BSD爱好者乐园G`8_ {^a~
        
    //std::cout << padd->result();
    TfLv/yc}
    *nT~*j)h2{'y$H    
    // 不做没有意义的转化BSD爱好者乐园)z Gto M m!v{@x6d/Y
        //// error
    lJG*R;k)T0FN
        //struct st{int i; double d;};BSD爱好者乐园 [UYDV0sp
        
    //st s;BSD爱好者乐园4y*z [IW%zfDE q
        
    //int x = (int)s; //c2440BSD爱好者乐园%V _#`M3{
    BSD爱好者乐园8F Yo&@h4s)\i
        
    //double y = 10.0;BSD爱好者乐园_K/SEa(r H;Y
        
    //int *p = (int*)y; // c2440BSD爱好者乐园7}/ls3F?s4?z)Gq
    }

    "N3ed Iin*e%]T0X 

    x*~o8tj&l.E

    l'\1g5~4@B@Uv3)static_cast在功能上基本上与C风格的类型转换一样强大,含义也一样。
    7@WC6C T7[Y s2V它也有功能上限制:BSD爱好者乐园5h1])SCqk0h'}7GY
    第一,不能兄弟间转化,父子间转化没有类型安全检查,有可能会导致运行时错误,父子兄弟的动态转化应该适用dynamic_cast;
    V | tXMA*e#}*m6J第二,不能去除const,适用专用的const_cast;BSD爱好者乐园{9U,w9^ w E^^hD
    第三,不能用于两个没有继承关系的类,当然实际上这样的转化也是没有意义的;BSD爱好者乐园vna*L3[@A]L
    第四,当然也不支持没有意义的转化,例如,你不能用static_cast象用C风格的类型转换一样把struct转换成int类型,或者把double类型转换成指针类型;

    D)X,_7gh$V(`3Lr

    -G:N-k f3KtW m!?:_!S4)const_cast,用来修改类型的const或volatile属性。

    pkj1ML#I"FM SK hh

    %mU0Qzd F适用:BSD爱好者乐园Q]+i.p"@.^t3@%W)vI
    第一,常量指针被转化成非常量指针,并且仍然指向原来的对象;BSD爱好者乐园a'\Ty W9[_qI
    第二,常量引用被转换成非常量引用,并且仍然指向原来的对象;
    /?i2t0rUP第三,常量对象被转换成非常量对象;
    BSD爱好者乐园7H#t9h+A:Jq5T`

    #Js `!csV(Y.L实例:BSD爱好者乐园(Z r\0G+g

    yK!\W/y|!Nf BSD爱好者乐园O olt sL#\

    Code
    b3z4G9z c PWF&Wvoid ConstCastTest()BSD爱好者乐园l3^+I/Cz1j]6M
    {BSD爱好者乐园*OO;`N!VEG%@
        
    const int* pa = new int(20);BSD爱好者乐园oGhYnj6})kN
        
    int *pb;BSD爱好者乐园%s3lwC \)_P&W
        pb 
    = const_cast<int*>(pa);BSD爱好者乐园9x0h Rk+b7[
        
    *pb = 30;BSD爱好者乐园"b'VMKsf5F%iMH!b
        std::cout 
    << *pa << std::endl;
    @9u3Xo5{}
    BSD爱好者乐园|V ^(`a M(K$kN)`

     BSD爱好者乐园1T"}ceD

    M4Wi"Fg X%f/u$k5)reinterpret_cast,此转型操作符的结果取决于编译器,用于修改操作数类型,非类型安全的转换符。
    !}^/{:ChT|适用:
    W,r7n;N~[jWY7\r一般不推荐使用,但是一般用来对函数指针的转化。
    [U4@9Co[%Z
    实例:BSD爱好者乐园,N/vtvCs;I

    BSD爱好者乐园d Ao:TnFe

     BSD爱好者乐园M@0`;A}2O\2a

    CodeBSD爱好者乐园?1T3T7X;RTK V(f \b
    // 不可以移植,不推荐使用
    1]/HSi`k|,v#N
    int ReinterpretTest()
    K t:f|4W3{3CzK2C{BSD爱好者乐园6_(P^7iDcG
        
    struct dat { short a; short b;};BSD爱好者乐园4l:]$E8JR*W [7uW
        
    long value = 0x00100020;BSD爱好者乐园[y @j3F)b G"t*T
        dat 
    * pd = reinterpret_cast<dat *> (&value);BSD爱好者乐园/`.L4m~ i
        std::cout 
    << pd-><< std::endl; // 0x0020BSD爱好者乐园 O3q4D:HYD W,r
        std::cout << pd-><< std::endl; // 0x0010BSD爱好者乐园9f-\5H wo`
        return 0;
    w VZ7Ck`)d%b l0G}BSD爱好者乐园 E5_Z]l2L
    BSD爱好者乐园o:X-Fs l?MY
    typedef 
    void (*Fun)();BSD爱好者乐园+g{0b L F'kOF"A+N3B

    S vB4Gmo|0?
    int Testing()
    N#h6iN#_0Kxo{
    ;wjPE5@*PG0it    std::cout 
    << "Testing" << std::endl;
    Tn[gM`"d ]    
    return 10;
    ~1V0d}H\m0p}
    ZOF(H6Ph
    U {M]5b"g`
    void ReinterpretTest2()
    2k'zD J3OE{
    *f7r eZm1[X    
    //Fun f = (Fun)Testing;
    V8N)o#jp.O8iE    
    //f();BSD爱好者乐园[V't"^Z
        Fun f = reinterpret_cast<Fun>(Testing);BSD爱好者乐园6b[:d)r1p V
        f();BSD爱好者乐园0J(qA9BE{ r E
    }

    (e9~0dM3v 

    X.d-W]? p+wuZ

    x'?$K-bS,B三 总结

    v L;C H{'D*MBSD爱好者乐园%{"Wd{;A7iQ

    在C++一般更推荐新加的static_cast,const_cast,dynamic_cast和reinterpret_cast转化方式;

    0qykS;d6r+i
    [版权声明]BSD爱好者乐园站内文章,如来源不是互联网,则均系原创或翻译之作,可随意转载,或以此为基础进行演译,但务必以链接形式注明原始出处和作者信息,否则属于侵权行为。另对本站转载他处文章,俱有说明,如有侵权请联系本人,本人将会在第一时间删除侵权文章。
     

    评分:0

    我来说两句

    seccode