C++ primer 笔记 第五章

表达式

表达式 = 操作数 + 操作符

表达式的结果一般为右值,可以读取该结果值,但是不允许对它进行赋值;

对于操作数为内置或复合类型的二元操作符,通常要求它的两个操作数具有相同的数据类型,或者其类型可以转换为同一种数据类型,比如int型可以转换为double类型;

  • 算数操作符

    左结合

  • 关系逻辑操作符

    逻辑与和逻辑或操作符总是先计算其左操作数,然后再计算其右操作数。只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数。称为“短路求值”;

    不能串接使用关系操作符;

  • 位操作符

    对于为操作符,由于系统不能确保如何处理其操作数的符号位,所以建议使用unsigned整型操作数

  • 赋值操作符

    赋值操作符的左操作数必须是非const的左值;

    右结合性;

  • 自增和自减操作符

    int i = 0, j;
    j = i++;  //j = 0, i = 1
    j = ++i;  //j = 2, i = 2
    //前置操作返回加1后的值,所以返回对象本身,这是左值。而后置操作返回的则是右值
    

    当我们希望在单个复合表达式中使用变量的当前值,然后再加1,通常使用后置++;

    • 在单个表达式中组合使用解引用和自增操作,可简化代码

      vector<int>::iterator iter = ivec.begin();
      while (iter != ivec.end())
      	cout<< *iter++ <<endl;
      //由于后自增操作的优先级高于解引用操作,*iter++等价于*(iter++),即先时iter加1,然后返回iter原值的副本作为该表达式的结果,因此,解引用操作的操作数式iter未加1前的副本
      
  • 操作符优先级

    • 复合表达式的处理原则:

      如果有怀疑,则在表达式上按程序逻辑顺序要求使用圆括号强制操作数的组合;

      如果要修改操作数的值,则不要在同一个语句的其他地方使用该操作数。如果必须使用改变的值,则把该表达式分割成两个独立语句:在一个语句中改变该操作数的值,再在下一个语句使用它

  • new 和 delete表达式

    动态创建对象得分默认初始化:

    string *ps = new string();  //初始化为空字符串
    int *pi = new int;		//未初始化
    int *pi = new int();	//初始化为0
    

    值初始化的()语法必须置于类型名的后面,而不是变量后;

    动态创建的对象用完后,必须显式地将该对象占用的内存返回给自由存储区;

    如果指针指向的不是new分配的内存地址,则在该指针上使用delete是不合法的;但如果指针的值是0,则是合法的;

    一旦删除了指针所指向的对象,立即将指针置为0,这样就非常清楚地表明指针不再指向任何对象。

    tips:三种常见的与动态内存分配有关的错误:

    • 删除指向动态分配内存的指针失败,因为无法将该块内存返还给自由存储区。称为“内存泄漏”,一般很难发现,只有等到程序运行一段时间后,耗尽了所有内存空间时,内存泄漏才会显露出来。
    • 读写已删除的对象。
    • 对同一个内存空间使用两次delete操作,自由存储区可能被破坏。
  • 类型转换

    • 隐式类型转换

      如果赋值操作的左右操作数类型不相同,则右操作数会被转换为左边的类型

      int val = 3.14;  //double类型的3.14被编译器自动转换为int类型的3
      
      //在混合类型的表达式中,其操作数被转换为相同的类型
      int ival;
      double dval;
      ival >= dval; 	//ival转换为double
      
      //用作条件的表达式被转换为bool类型
      int ival;
      if(ival)		//ival转换为bool
      which(cin)		//cin转换为bool
          
      //用一表达式初始化某个变量,或将一表达式赋给某个变量,该表达式被转换为该变量的类型
      int ival = 3.14 + 3;
      
    • 算术转换

      转换规则定义了一个类型转换层次,该层次规定了操作数应按什么次序转换为表达式中最宽的类型

      bool  flag;			char 		   cval;
      short sval;			unsigned short usval;
      int   ival;			unsigned int   uival;
      long  lval;			unsigned long  ulval;
      float fval;			unsigned float ufval;
      3.14159L + 'a';  //'a'->int->double
      dval + ival;	 //ival->double
      dval + fval;	 //fval->double
      ival = dval;	 //dval->int  截断
      flag = dval;	 //if dval is 0,then flag is false,otherwise true
      cval + fval;	 //cval->int->float
      sval + cval;	 //sval and cval ->int
      cval + lval;	 //cval->long
      ival + ulval;	 //ival->unsigned long
      usval + ival;	 //取决于unsigned 和 int的大小 
      uival + lval;	 //取决于unsigned int和long的大小
      
    • 指针转换

      使用数组时,一般数组会自动转换为指向第一个元素的指针;例外:对数组取地址(&)或sizeof或数组对数组的引用进行初始化时,不会将数组转换为指针;

      指向任意类型的指针都可转换为viod*类型;整型数值常量0可转换为任意指针类型;

    • 转换为bool类型

      算术值和指针值都可以转换为bool类型;bool类型也可转换为int型 false–0 true–1;

    • 转换为const对象

      int i;
      const int ci = 0;
      const int &j = i;		//ok 将非const转换为const
      const int *p = &ci;		//ok 将非const对象的地址(或指针)转换为指向相关const类型的指针
      
    • 显式(强制)类型转换 cast

      cast-name (表达式)

      • dynamic_cast

        支持运行时识别指针或引用所指向的对象,可将基类类型的指针或引用安全地转换为派生类型的指针或引用

      • const_cast

        转换掉表达式的const性质

      • static_cast

        将一个较大的算术类型赋给较小的类型时有用,强制转换的结果应与原来的地址值相等

      • reinterpret_cast

        通常为操作数的位模式提供较低层次的重新解释

      tips:避免使用强制类型转换,如果非强制转换不可,则应限制强制转换值得作用域,并记录所有假定涉及的类型,这样能减少错误的发生

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值