zoukankan      html  css  js  c++  java
  • C++中的四种转型操作符

    在具体介绍C++中的四种转型操作符之前,我们先来说说旧式转型的缺点:

    ①它差点儿同意将不论什么类型转换为不论什么其它类型,这是十分拙劣的。假设每次转型都可以更精确地指明意图,则更好。

    ②旧式转型难以辨识。旧式转型的语法结构是由一对小括号加上一个对象名称组成。而小括号和对象名称在C++的不论什么地方都有可能被使用。

    为解决C旧式转型的缺点,C++导入了4个新的转型操作符:static_cast、const_cast、dynamic_cast、reinterpret_cast。

    以下我来一一分析这四种转型操作符。

    1)static_cast

    static_cast基本上拥有与C旧式转型同样的威力与意义,以及同样的限制。

    比如。不可以利用static_cast将一个struct转型为int。或将一个double转型为pointer;这些都是C旧式转型动作原本就不可以完毕的任务。

    static_cast甚至不可以移除表达式的常量性。

    int a,b;

    ...

    double c = static_cast<double>(a)/b;

    2)const_cast

    const_cast用来改变表达式中的常量性(constness)或变易性(volatileness)。使用const_cast,便是对人类(以及编译器)强调,通过这个转型操作符,我们唯一想改变的是某物的常量性或变易性。

    假设将const_cast应用于上述以为的用途。那么转型动作会被拒绝。以下看一个样例:

    class Widget{...};

    class SpecialWidget:public Widget {...};

    void update(SpecialWidget* psw);

    SpecialWidget sw;//sw是个non-const对象

    const SpecialWidget& csw = sw;//csw却是一个代表sw的reference。并视之为一个const对象

    update(&csw);//错误!

    不能讲const SpecialWidget*传给一个须要SpecialWidget*的函数

    update(const_cast<SpecialWidget*>(&csw));//可!

    &csw的常量性被去除了。也因此,csw(亦即sw)在此函数中可被更改。

    update((SpecialWidget*)&csw);//情况同上,但使用的是较难辨识的c旧式转型语法

    Widget* pw = new SpecialWidget;

    update(pw);//错误!pw的类型是Widget*,但update()须要的却是SpecialWidget*。

    update(const_cast<SpecialWidgt*>(pw));//错误!const_cast仅仅能用来影响常量性或变易性,无法进行继承体系的向下转型动作。

    3)dynamic_cast

    ①dynamic_cast用来运行继承体系中”安全地向下转型或跨系转型动作“。

    也就是说你能够利用dynamic_cast。将”指向base class objects的pointers或references“转型为”指向derived(或sibling base)class objects的pointers或references“,并得知转型是否成功。

    假设转型失败,会以一个null指针(当转型对象是指针)或一个exception(当转型对象是reference)表现出来:

    Widget* pw;

    ...

    update(dynamic_cast<SpecialWidget*>(pw));//非常好,传给update()一个指针,指向pw所指的SpecialWidget----假设pw真的指向这种东西。否则传过去的将是一个null指针

    void updateViaRef(SpecialWidget& rsw);

    updateViaRef(dynamic_cast<SpecialWidget&>(*pw));//非常好。传给updateViaRef()的是pw所指的SpecialWidget----假设pw真的指向这种东西;否则抛出一个exception

    dynamic_cast仅仅能用来助你巡航于继承体系之下。它无法应用在缺乏虚函数的类型身上,也不能改变类型的常量性。

    ②dynamic_cast的第二个用途是找出被某对象占用的内存的起始点。比如:

    class HeapTracked

    {

    public:

         bool isOnheap() const;

    private:

         typedef const void* RawAddress;

         static list<RawAddress> addresses;

    };

    bool HeapTracked::isOnheap() const

    {

        const void* rawAddress = dynamic_cast<const void*>(this);//取得一个指针,指向*this所占内存的起始处

        list<RawAddress>::iterator it = find(addresses.begin(),addresses.end(),rawAddress);

        return it != addresses.end();

    }

    凡涉及”多重继承或虚拟基类“的对象,会拥有多个地址,仅仅要简单地将指针”动态转型“为void*(或const void*或volatile void*或const volatile void*),便会获得一个指针,指向”原指针所指对象“的内存起始处。

    只是,dynamic_cast仅仅适用于那种”所指对象至少有一个虚函数“的指针身上。

    4)reinterpret_cast

    这个操作符的转换结果差点儿总是与编译平台息息相关。所以reinterpret_cast不具移植性。

    reinterpret_cast的最经常使用用途是转换”函数指针“类型。

    如果有一个数组。存储的都是函数指针。有特定的类型:

    typedef void (*FuncPtr)();//FuncPtr是个指针,指向某个函数。

    FuncPtr funcPtrArray[10];//funcPtrArray是个数组,内有10个FuncPtrs。

    如果因为某种原因,你希望将下面函数的一个指针放进funcPtrArray中:

    int doSomething();

    假设没有转型。不可能办到这一点,由于doSomething的类型与funcPtrArray所能接受的不同。

    funcPtrArray内各函数指针所指函数的返回值是void,但doSomething的返回值却是int:

    funPtrArray[0] = &doSomething;//错误!类型不正确

    使用reinterpret_cast,能够强迫编译器了解你的意图。

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

    函数指针的转型动作并不具有移植性(C++不保证全部的函数指针都能以此方式又一次呈现),某些情况下这种转型可能会导致不对的结果,所以应该尽量避免将函数指针转型。

    假设编译器尚未支持这些新式转型动作,也能够使用传统转型方式代替static_cast、const_cast和reinterpret_cast。甚至能够利用宏来仿真这些新语法。

    #define static_cast(TYPE,EXPR) ((TYPE)(EXPR))

    #define const_cast(TYPE,EXPR) ((TYPE)(EXPR))

    #define reinterpret_cast(TYPE,EXPR) ((TYPE)(EXPR))

    至于dynamic_cast,也可回头使用旧式的C型语法。或者定义一个宏。可是它们不可能告诉你转型是否成功。

  • 相关阅读:
    洛谷 P1414 又是毕业季II Label:None
    洛谷 P1372 又是毕业季I Label:None
    洛谷 P1111 修复公路 Label:并查集
    高精度特别策划 加减乘除余~~~
    洛谷 P1967 货车运输 Label: 倍增LCA && 最小瓶颈路
    数组指针和指针数组的区别
    堆和栈的区别
    JAVA8 十大新特性详解
    自己在菜单栏中加了一项打开文件的菜单后窗口不刷新 单击才刷新
    Windows 7 OpenGL配置
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5241696.html
Copyright © 2011-2022 走看看