C++ primer 笔记 第五章

    技术2022-07-11  89

    表达式

    表达式 = 操作数 + 操作符

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

    对于操作数为内置或复合类型的二元操作符,通常要求它的两个操作数具有相同的数据类型,或者其类型可以转换为同一种数据类型,比如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:避免使用强制类型转换,如果非强制转换不可,则应限制强制转换值得作用域,并记录所有假定涉及的类型,这样能减少错误的发生

    Processed: 0.010, SQL: 9