zoukankan      html  css  js  c++  java
  • C++_新特性1-类型转换运算符

    C++的创始人认为C语言的类型转换运算符太过于松散。他采取了更加严格的限制允许的类型转换。并添加了4个类型转换运算符。

    这部分特性比较高阶,我把它归于奇技淫巧的范畴。这里简单介绍一下,以后实际有用到再深入研究。

    struct Data

    {

      double data[200];

    };

    struct Junk

    {

      int junk[100];

    };

    Data d = {2.5e33, 3.5e-19, 20.2e32};

    char * pch = (char *) (&d);    //type cast #1

    char ch = char (&d);              //type cast #2

    Junk * pj = (Junk *) (&d);       //type cast #3

    首先,上述3种类型转换中,哪一种更有意义?除非不讲理,否则它们中没有一个是有意义的。其次,这3种类型转换中哪种是允许的呢?在C语言中都是允许的。

    对于这种松散的情况,Stroustrop采取的措施是,更严格地限制允许的类型转换,并添加4个类型转换运算符,使转换过程更加规范:

    dynamic_cast;

    const_cast;

    static_cast;

    reinterpret_cast;

    可以根据目的选择一个合适的运算符,而不是使用通用的类型转换。

    这指出了进行类型转换的原因,并让编译器能够检查程序的行为是否与设计者想法吻合。

     ======================================================

    举个例子dynamic_cast运算符在前面已经介绍过了,假设High和Low是两个类,而ph和pl的类型分别为High *和Low *。

    则仅当Low是High的可访问基类时,下面的语句才将一个Low*指针赋给pl:

    pl = dynamic_cast<Low *> ph;

    否则,该语句将空指针赋给pl。

    该运算符的语法如下:

    dynamic_cast <type_name> (expression)

    该运算符的用途是,使得能够在类层次结构中进行向上转换(由于是is-a关系,这种转换是安全的),而不允许其他转换。

      ======================================================

    const运算符用于执行只有一种用途的类型转换。

    即改变值为const或volatile,其语法与dynamic_cast运算符相同:

    const_cast <type_name>(expression)

    如果类型的其他方面也被修改,则上述类型的转换将出错。

    也就是说除了const和volatile特征可以不同外,type_name和expression的类型必须相同。

    再次假设High和Low是两个类:

    High bar;

    const High * pbar = &bar;

    ...

    High * pb = const_cast<High *> (pbar);                     //valid

    const  Low * pl = const_cast<const Low *> (pbar);   //invalid

    第一个类型转换使得*pb成为一个可用于修改bar对象值的指针,它删除const标签。

    第二个类型转换是非法的,因为它同时尝试将类型从const High*改为const Low*。

    提供该运算符的原因是,有时候可能需要这样一个值,它在大多数时候是常量,而有时又是可修改的。

    在这种情况下,可以将这个值声明为const,并在需要修改它的时候,使用const_cast

    这也可以通过通过类型转换实现,但通用转换也可能同时改变类型:

    High bar;

    const High * pbar = &bar;

    ...

    High * pb =(High *)(pbar);

    Low * pl = (Low *) (pbar);    

    由于编程时可能无意间同时改变类型和常量特征因此使用const_cast运算符更安全

    const_cast不是万能的。它可以修改指向一个值的值,但修改const的值的结果是不确定的。

     1 //constcast.cpp  -- using const_cast<>
     2 #include <iostream>
     3 using std::cout;
     4 using std::endl;
     5 
     6 void change(const int * pt, int n);
     7 
     8 int main()
     9 {
    10     int popl = 38383;
    11     const int pop2 = 2000;
    12 
    13     cout<<"pop1, pop2:"<<pop1<<", "<<pop2<<endl;
    14     change(&pop1, -103);
    15     change(&pop2, -103);
    16     cout<<"pop1, pop2:"<<pop1<<", "<<pop2<<endl;
    17     return 0;
    18 }
    19 
    20 void change(const int * pt, int n)
    21 {
    22     int * pc;
    23     pc = const_cast<int *>(pt);
    24     *pc += n;
    25 }

    const_cast运算符可以删除const int *中的const,使得编译器能够接受change()中的语句:

    *pc += n;

    但由于pop2被声明为const,因此编译器可能禁止修改它,如下面的输出所示:

    pop1, pop2 : 38383, 2000

    pop1, pop2 : 38280, 2000

    正如您所看到的,调用change()时,修改了pop1,但没有修改pop2.。

    在change()中,指针被声明为const int * ,因此不能用来修改指向的int。

    指针pc删除了const特征,因此可用来修改指向的值,但仅当指向的值不是const时才行。

    因此,pc可用于修改pop1,但不能用于修改pop2。

      ======================================================

    static_cast运算符的语法与其他类型转换运算符相同:

    static_cast <type-name> (expression)

    仅当type_name可被隐式转换为expression所属的类型或expression可被隐式转换为type_name所属的类型时,上述转换才是合法的,否则将会出错。

    假设High是Low的基类,而Pond是一个无关的类,则从High到Low的转换,从Low到High的转换都是合法的,而从Low到Pond的转换时不允许的。

    High bar;

    Low blow;

    ...

    High * pb = static_cast<High *> (&blow);    //valid upcast

    Low * pl = static_cast<Low *>(&bar);    //valid downcast

    Pond * pmer = static_cast<Pond *>(&blow);   //invalid, Pond unrelated

    第一种转换是合法的,因为向上转换可以显式地进行。

    第二种转换是从基类指针到派生类指针,在不进行显式转换的情况下,将无法进行。但由于无需进行类型转换,便可以进行另一个方向的类型转换,因此使用static_cast进行向下转换是合法的。

    同理,由于无需进行类型转换,枚举值就可以被转换为整型,所以可以用static_cast将整型转换为枚举值。同样,可以使用static_cast将double转换为int、将float转换为long以及其他各种数值转换。

     //完全被绕晕了

      ======================================================

    reinterpret_cast运算符用于天生危险的类型转换。它不允许删除const,但会执行其他令人生厌的操作。

    有时程序员必须做一些依赖于实现的、令人生厌的操作,使用reinterpret_cast运算符可以简化对这种行为的跟踪工作。该运算符的语法与另外3个相同:

    reinterpret_cast <type-name> (expression)

    下面是一个使用示例:

    struct dat { short a; short b;}

    long value = 0xA224B118;

    dat * pd = reinterpret_cast<dat *> (&value);

    cout << hex << pd->a;  //display first 2 bytes of value

    通常,这样的转换适用于依赖于实现的底层编程技术,是不可移植的。

    例如,不同系统在存储多字节整型时,可能以不同的顺序存储其中的字节。

    然而,reinterpret_cast运算符并不支持所有的类型转换。例如,可以将指针类型转换为足以存储指针表示的整型,但不能将指针转换为更小的整型或浮点型。

    另一个限制是,不能将函数指针转换为数据指针,反之亦然。

      在C++中,普通类型转换也受到限制。基本上,可以执行其他类型转换可执行的操作,加上一些组合,如static_cast或reintepret_cast后跟const_cast,但不能执行其他转换。

    因此,下面的类型转换在C语言中是允许的,但在C++中通常不允许,因为对于多数C++shixian ,char类型都太小,不能存储指针。

    char ch =char (&d)    //type cast #2 - convert address to a char

    这些限制是合理的,如果您觉得这种限制难以忍受,可以使用C语言。

    //这段也是晦涩难懂

  • 相关阅读:
    Redis 扛 Mysq 并发方案小记
    CURL 访问 HTTPS 的坑 [后记]
    PHP CURL HTTPS Error: "SSL certificate problem: unable to get local issuer certificate"
    PHP 使用 cURL HTTPS 协议证书认证问题
    HTTPS 学习笔记 (1)
    Windows CMD 仿 Mac Terminal open 命令 打开指定目录资源管理器
    Win10 Hyper-V 配置
    Windows10 下精简和配置 MySQL 5.6
    Win10 + Nginx 1.10 + PHP 7 + Redis 配置方法
    sublime text 配置 builder [build system]
  • 原文地址:https://www.cnblogs.com/grooovvve/p/10422216.html
Copyright © 2011-2022 走看看