• C++ primer 5th : 第四章笔记


    第四章: 表达式

      基本概念:

        运算符:  一元 , 二元 , 三元

        组合运算符 和 运算对象 : 

            优先级:  使用  () 避免优先级的混淆的问题

            结合律:  

            求值顺序: 二元运算符两边的表达式计算顺序可能存在差异 , 应该避免

        对优先级 , 结合率 , 求值顺序的解释:

            

     //如下表达式:
     //我们假设 g() 的操作是将全局变量 i = 10 的值 乘以 2 返回
     //我们假设 h() 的操作是将全剧变量 i 的值 + 2 返回
    f() + g() * h() + j()
    
    
    // 优先级 : 存在于组合运算当中 , 也就是多个运算符参与 , 优先级是运算符 与 运算符之间的关系
    
    // 结合率 : 我们针对 上述表达式 可以 使用 结合率 的方式改变运算符的优先级
    // ( f() + g() ) * h() + j()
    
    // 求值顺序 : 对于 单个二元运算符来说 , 先算右边 还是 先算左边 好像只有在 逻辑运算符  :   ||   && 上才有体现 , 但是在 * 上可能存在差异 , 如上 , 
    // 如果我们先算左边 , 在算右边 ; 那 g() * h() 的结果就是 20 * 22  = 440
    // 如果我们先算右边  ,   在算左边 ; 那 g() * h() 的结果就是 24  *12 = 288
    //  所以我觉得 能不在一个运算符两边修改 共有的部分 是最好的。

        运算对象转换 :

            表达式中匀允许不同类型之间的转换 , 编译器会自动的转换

            int 还会有类型提升

            在算术类型之间的运算 需要保证 运算结果不溢出 , 且精度损失降低到最小 , 才有运算结果的类型一定是其中的最高类型。

        重载运算符:

            将运算符 赋予 在某一个非基本类型上面新的含义

        左值 与 右值 :

            将一个对象当作左值来使用 : 代表的是当前对象本身

            将一个对象当作右值来使用 : 代表的是当前对象的拷贝

            需要右值的地方可以使用 左值代替 , 但是反过来通常不行

           decltype 与 左值 右值:

            如果 decltype 的是一个左值类型 , 那么得到一定是一个引用类型 , 如果decltype 的是一个右值类型 , 那么得到的一定是一个 普通类型

    #include <iostream>
      
    using namespace std;
    
    int main()
    {
        int a = 10;         //普通的类新  int
        int & b = a;        //引用类型    int &
        decltype(b) c = a;  //c 的类型为  int &
        c = 20;             //修改C 就是 修改a
        cout << a << endl;  //结果为20
        return 0;
    }
    ~       
    decltype 的是的左值类型

    算数运算符:

      略


    逻辑运算符:

      注意 : &&  || 有运算符求值顺序的规定 , 先算左边在算右边 ,  左边满足的顺序右边不再计算 , 这就是短路


    赋值运算符:

      •  = 左边必须是一个可以修改的左值
      • C++11 允许使用 {} 扩起来的初始值列表做右值
      • 连续赋值运算 满足 右边结合率 : a = b = 10
      • 赋值运算符优先级低 : if (  1 != (i = get_value()) 

    递增运算符 和 递减运算符:

      •  ++ , --  运算符 需要左值对象 :   (i++)++ 错误 , i++返回的是右值

    成员运算符:

      . 与 ->


    条件运算符:

      >  , <  , >=  ......


    位运算:

      & , | , ~ , ^


     sizeof 运算符:

      sizeof(类型) 可以获得该类型占用的内存大小 , C++ 可以让sizeof 直接访问 类的成员的  , 以此的其成员类型占用的内存的大小.  sizeof (class::number)

    •  sizeof(数组) : 数组不会退化成指针)
    •    sizeof(类类型) : 固有成员的内存和 : 不包括成员指向的 堆空间的内存
    •    sizeof  返回的类型是一个 constexpr

    逗号运算符:

      结合律从左边向右边 , 最后的结果为最右边的表达式子 , 且如果最右边的表达式是左值 , 整个表达式结果为左值  , 否则为右值


    类型转换:

      如果两个类型之间可以相互转换 , 那么他们就是有关联的.

      无须程序员的介入的类型转换称为隐式类型转换.

      

      显式类型转换:

        static_cast<>():

            不能擦除引用 , 指针 的 底层 const 属性。

            大范围类型 向 小范围类型 ,  高精度 向 低精度  : 告诉编译器我是故意转换的 , 而且我能确保这样作的后果没有问题 , 你把警告给我关了吧

        const_cast<>():

            只能改变对象的顶层const属性 , 不能值类型转换:

            只有当底层const指向的对象不是 const ,  才能进行擦除const :

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int a = 10;                      //a 为非const
        const int & b = a;               //底层const , 但是 a 为非const
        int & c = const_cast<int &>(b);  //我们可以擦除掉const 属性
        c = 30;
        cout << a << endl;               //30 : 成功修改
    
    
        const int aa = 10;                //aa为const
        const int & bb = aa;              //指出底层const ,底层确实也是const
        int & cc = const_cast<int &>(bb); //擦除掉底层的const , 但是为cc重新开辟了空间,也就是 cc 和 aa 指向不是同一个内存区域了
        cout << aa << endl;               //10
        cout << cc << endl;
        return 0;
    }

        dynamic_cast<>()

          用于具有继承体系之间的转换  指针和引用 , 类必须具有虚函数  ,  父类指针指向的 子类对象向 向子类指针转换 ,  或者父类引用指向子类的向子类引用转换使用:

          父类指针 指向父类型对象 向 子类型指针转换 |   一个父类的两个子类之间转换   最后为 NULL

          父类引用 指向父类型对象 向 子类型引用转换 抛出 std::bad_cast 异常

           

    #include <iostream>
    
    class A{
    public:
      virtual ~A(){}  
    }
    class B :public A{
    };
    class C :public A{
    };
    
    
    int main()
    {
        C * c = new C();
        B * b = new B();
        A * a = new A();
    
        B *bc = dynamic_cast<B*>(c);    //2个子类之间不能 dynamic_cast
        if(NULL == bc)
        {
            cout <<"2 个子类指针之间不能发生转换!" << endl;
        }
    
        B *ba = dynamic_cast<B*>(a);    //父类转换成子类 , 不安全
        if(NULL == ba)
        {
            cout <<"父类指针 指向 父类对象 不能向子类指针转换!"<<endl;
        }
        A ra;
        A & aa = ra;
        try{
            B & b = dynamic_cast<B &>(aa);
        }catch(std::bad_cast){
            cout <<"父类引用  指向 父类对象  不能向子类引用转换!" <<endl;
        }
        return 0;
    
    }
    
    输出结果 : 
    2 个子类指针之间不能发生转换!
    父类指针 指向 父类对象 不能向子类指针转换!
    父类引用  指向 父类对象  不能向子类引用转换!

        reinterpret_cast<>():

          不建议使用 

  • 相关阅读:
    [BZOJ2661][BeiJing wc2012]连连看 费用流
    <meta> 标签
    CSS3 Transitions, Transforms和Animation的使用
    word-wrap和word-break的区别吗?
    css3中比较少用到的属性记录
    CSS ::Selection的使用方法
    CSS 属性
    javascript正则表达式语法
    jquery metadata 详解
    关于window.console&&console.log(123)的思考
  • 原文地址:https://www.cnblogs.com/Geek-Z/p/9935424.html
Copyright © 2020-2023  润新知