• static_cast与dynamic_cast转换


    static_cast与dynamic_cast转换  

           

    一 C语言中存在着两种类型转换:

    隐式转换和显式转换

    隐式转换:不同数据类型之间赋值和运算,函数调用传递参数……编译器完成

    char ch;
    int i = ch;

    显示转换:在类型前增加 :(Type)变量 对变量进行的转换。用户显式增加

    char *pc = (char*)pb;
    void *ps = (void*)pa;


    二 C++
    中的类型转换

      通过这两种方式,C语言中大部分的类型转换都可以顺利进行。

    至于能不能进行转换,转换后的结果如何,编译器不管需要用户自己去控制。

      C++继承了C中的隐式和显式转换的方式。但这种转换并不是安全和严格的,

    加上C++本身对象模型的复杂性,C++增加了四个显示转换的关键字。(C++是强类型语言)

    static_castdynamic_castconst_staticreinterpret_cast

    1 static_cast

    (1)用于基本的数据类型转换(char,int),及指针之间的转换

    复制代码
    test_enum type = test_enum_1;

    char a ;
    int b = static_cast<int>(a);
    char c = static_cast<char>(b);
    type = static_cast<test_enum>(b);

    char* pa = NULL;
    int *pb = (int*)pa;
    //int *pb = static_cast<int*>(pa); //error
    //pa = static_cast<char*>(pb) //error
    char *pc = (char*)pb;
    //char *pc = static_cast<char*>(pb); //error

    void *p = static_cast<void*>(pa);
    pb = static_cast<int*>(p);
    pc = static_cast<char*>(p);
    复制代码

     

    (2)类层次中基类与子类成员函数指针的转换

    复制代码
    class A
    {

    public:
    void set(){}
    };

    class B:public A
    {
    public:
    void set(){}
    };

    typedef void (A::*PS_MFunc)();   //指向类A的成员函数指针

    PS_MFunc func = &A::set;
    func = static_cast<PS_MFunc>(&B::set); //基类指向子类成员函数指针,必须进行转换
    复制代码


    (3)类层次结构中基类与子类指针或引用之间的转换  

       上行转换:子类指针或引用转换成基类表示——安全

      下行转换:基类指针或引用转换成子类表示——危险(没有动态类型检查)

    复制代码
    class A
    {
    };
    class B:public A
    {
    };
    class C:public A
    {
    };
    class D
    {
    };

    A objA;
    B objB;
    A* pObjA = new A();
    B* pObjB = new B();
    C* pObjC = new C();
    D* pObjD = new D();

    objA = static_cast<A&>(objB); //转换为基类引用
    objA = static_cast<A>(objB);
    objB = static_cast<B>(objA); //error 不能进行转换

    pObjA = pObjB; //right 基类指针指向子类对象
    //objB = objA; //error 子类指针指向基类对象
    pObjA = static_cast<A*>(pObjB); //right 基类指针指向子类
    pObjB = static_cast<B*>(pObjA); //强制转换 OK 基类到子类
    //pObjC = static_cast<C*>(pObjB); //error 继承于统一类的派生指针之间转换
    //pObjD = static_cast<D*>(pObjC); //error 两个无关联之间转换
    复制代码

    2 dynamic_cast

    (1)继承关系的类指针对象或引用之间转换

            

    复制代码
    class A
    {
    };
    class B:public A
    {
    };
    class C:public A
    {
    };
    class D
    {
    };

    A objA;
    B objB;
    A* pObjA = new A();
    B* pObjB = new B();
    C* pObjC = new C();
    D* pObjD = new D();
    //objA = dynamic_cast<A>(objB); //error 非引用

    objA = dynamic_cast<A&>(objB);
    //objB = dynamic_cast<B&>(objA); //error A 不是多态类型不能转换 若有虚函数则可以进行转换

    pObjA = dynamic_cast<A*>(pObjB);
    //pObjB = dynamic_cast<B*>(pObjA); //error A 继承关系 不是多态类型不能转换
    //pObjB = dynamic_cast<B*>(pObjC); //error C 兄弟关系 不是多态类型不能转换
    //pObjB = dynamic_cast<B*>(pObjD); //error D 没有关系 不是多态类型不能转换
    复制代码

    (2)包含有虚函数之间对象指针的转换   

    复制代码
    class A
    {
    Public:
    Virtual ~A(){}
    };
    class B:public A
    {
    };
    class C:public A
    {
    };
    class D
    {
    Public:
    Virtual ~D(){}
    };
    pObjB = dynamic_cast<B*>(pObjA);    // worning 继承关系 父类具有虚函数 多态
    pObjB = dynamic_cast<B*>(pObjD); //worning 没有关系 D是多态类型可以转换
    //以上结果:pObjB == NULL 此处会发生一个运行时错误
    复制代码

             也就是说除了基类指针指向子类对象,可以没有虚函数外,其它要进行dynamic_cast转换必须具有虚函数才行。

    那这是为什么呢?下面继续>

     

    (3)dynam_cast转换的安全性

             dynamic_cast是动态转换,只有在基类指针转换为子类指针时才有意义。

    (子类指针转换为基类指针本来就是可以的:基类指针指向子类对象OK)。

    但是基类指针转换为子类指针,并不是每一次都有效:只有基类指针本身指向的是一个派生类的对象,

    然后将此基类指针转换为对应的派生类指针才是有效的。这种情况在表面上是无法判定的。此时dynamic就发挥了作用。

    情况1: static_cast转换       

    复制代码
    class A
    {
    };
    class B:public A
    {
    public:
    int m; //B 成员
    };

    A* pObjA = new A();
    B* pObjB = NULL;
    pObjB = static_cast<B*>(pObjA); //基类指针转化为子类指针 成功转换
    pObjB->m = 10;   //实际中pObj所指向的对象 是A类对象
    //上面会发生什么呢,在VC6.0中正常运行。。。?

    //如果:

    pObjB = dynamic_cast<B*>(pObjA); //error 基类A没有虚函数 不构成多态
    复制代码

    情况2:     dynamic_cast转换    

    复制代码
    class A
    {
    public:
    virtual ~A(){} //虚函数 多态
    };
    class B:public A
    {
    public:
    int m;
    };

    A* pObjA = new A();
    B* pObjB = NULL;
    pObjB = dynamic_cast<B*>(pObjA); //编译通过
    //实际运行结果:pObjB == NULL // dynamic_cast保证转换无效 返回NULL
    复制代码

             dynamic_cast转换不成功,则返回0

    4 虚函数对于dynamic_cast转换的作用

      为何使用dynamic_cast转换类指针时,需要虚函数呢。

    Dynamic_cast转换是在运行时进行转换,运行时转换就需要知道类对象的信息(继承关系等)。

    如何在运行时获取到这个信息——虚函数表。

      C++对象模型中,对象实例最前面的就是虚函数表指针,

    通过这个指针可以获取到该类对象的所有虚函数,包括父类的。

    因为派生类会继承基类的虚函数表,所以通过这个虚函数表,我们就可以知道该类对象的父类,在转换的时候就可以用来判断对象有无继承关系。

      所以虚函数对于正确的基类指针转换为子类指针是非常重要的。

     
  • 相关阅读:
    [每日电路图] 2、红外遥控电路原理设计与解析【转+解读】
    [每日电路图] 1、基于AT89C52单片机最小系统接口电路【转】
    [nRF51822] 5、 霸屏了——详解nRF51 SDK中的GPIOTE(从GPIO电平变化到产生中断事件的流程详解)
    [nRF51822] 4、 图解nRF51 SDK中的Schedule handling library 和Timer library
    [nRF51822] 3、 新年也来个总结——图解nRF51 SDK中的Button handling library和FIFO library
    [MFC] VS2013版本MFC工程移植到VC6.0上
    [异常解决] ubuntu上安采用sudo启动的firefox,ibus输入法失效问题解决
    [编译] 1、第一个makefile简单例子
    nginx静态文件不设置缓存
    Docker容器挂载文件(转载)
  • 原文地址:https://www.cnblogs.com/yuanming/p/7063672.html
Copyright © 2020-2023  润新知