S04表达式

来源:互联网 发布:snmp用php编程实现 编辑:程序博客网 时间:2024/05/22 06:53

S04表达式


一、基础

1、重载运算符:当运算符作用于类类型的运算对象时,用户可以自定义其含义,相当于为已存在的运算符赋予了另外一层含义,故称重载运算符;运算对象类型和返回类型都可以自定义,但是运算对象个数、优先级、结合律是无法自定义的

2、左值和右值:当一个对象被用作右值时,用的是对象的值(内容);当对象被用作左值时,用的是对象的身份(在内存中的位置)

注意:判断左值和右值的方法如下

  • Scott Meyers方法:能否取它的地址,能取地址的就是左值
  • Joseph Mansfield方法:左值可看作是“对象”,右值可看作是“值”;左值到右值的转换可看做“读出对象的值;std::move 允许把任何表达式以“值”的方式处理;std::forward 允许在处理的同时,保留表达式为“对象”还是“值”的特性,参见S16模板与泛型编程

二、算术运算符

1、m % n结果的符号与m相同

三、逻辑与关系运算符

1、短路求值:对逻辑与,当且仅当左侧为真时再求右侧;对逻辑或,当且仅当左侧为假时再求右侧

四、赋值运算符

1、赋值运算符的左侧对象必须是一个可修改的左值;且如果两侧类型不同,右侧对象将转换成左侧对象的类型

2、赋值运算满足右结合律

五、递增和递减运算符

1、很多迭代器不支持算术运算,必须用递增/递减运算

++iter;             //正确iter = iter + 1;    //错误,虽然与上式逻辑上等效,但是iter可能不支持算术运算

2、注意区分++ii++效果的差异,因此尽可能避免i++而只使用++i(除了部分场景下可以使用*p++

int i = 0, j;j = ++i;           //i = 1, j = 1; i先自增,再取值,此时对象本身作为左值返回j = i++;           //j = 1, i = 2; i先取值,再自增,此时对象原始值的副本作为右值返回

六、成员访问运算符

1、解引用*的优先级低于成员访问.优先级,因此(*p).size()p->size()而不要误用*p.size()

七、条件运算符

1、当条件运算符的两个表达式都是左值或者能够转换成同一种左值类型时,运算的结果是左值;否则运算的结果是右值

2、条件运算符的优先级极低,为了避免错误最好带上括号(cond ? expr1 : expr2)

八、位运算符

1、移位运算符(重载版本:I/O运算符)满足左结合律

九、sizeof运算符

1、sizeof(type)sizeof expr,后者返回表达式expr结果类型的大小,不实际计算expr

2、对引用类型运算返回被引用对象所占空间的大小

3、对指针运算返回指针本身所占空间的大小

4、对解指针运算返回指针所指对象所占空间的大小,即使是无效指针也可以,因为并不实际使用该指针

5、对数组名运算返回整个数组占用空间,此时不会把数组名隐式转换为指针

6、对stringvector对象运算返回该类型固定部分占用的空间,不计算其中元素占用空间(无论元素存在与否),求元素占用可以使用.size()方法

十、逗号运算符

1、按顺序求值,最终整个逗号表达式的值为最右侧表达式的值

十一、类型转换

1、算数转换:程序尽可能保持精度

2、隐式转换:数组转换成指针、类类型定义的转换等

3、显式转换:cast-name<type>(expression)type是目标类型,cast-name是转换模式,expression是待转换值(如果type是引用类型,则转换结果是左值)

(1)static_cast:任何具有明确定义的类型转换只要不包含底层const都可以

void *p = &d;  //正确,任何非常量对象的地址都能存入void *double *dp = static_cast<double*>(p); 

(2)const_cast:只能改变运算对象的底层const,常常用于有函数重载的场合

const char *pc;char *p = const_cast<char*>(pc);     //正确,但是通过p写值是未定义的行为const_cast<string>(pc);              //错误,const_cast只能用在去除底层const上//利用const_cast和static_cast实现类内非const成员函数调用const成员函数class Test{public:    ... //其他成员定义    const char &operator[](size_t val) const    {        //完成复杂的工作        do_somethings                   return text[val];    }    //利用非const成员函数调用const成员函数,避免重复do_somethings    char &operator[](size_t val)    {        //传入的是non-const的对象*this,使用static_cast转成const的*this再调用const operator[]        //(不加上const会导致递归调用自身)        //调用完成返回的是const char &,使用const_cast将常量引用去掉const,返回char &        return const_cast<char &>(static_cast<const Test &>(*this)[val]);    }}

(3)reinterpret_cast:通常为运算对象的位模式提供较低层次上的重新解释(非常危险尽可能避免使用)

int *ip;char *pc = reinterpret_cast<char*>(ip);   //注意虽然类型转换,但是实际上pc所指的真实对象是int而非char

(4)dynamic_cast:支持运行时类型识别(RTTI),将基类的指针/引用转换为派生类的指针/引用,参考S19特殊工具和技术

注意:除了函数重载场合使用const_cast,其他情况下都应尽可能避免使用强制类型转换

十二、运算符优先级表

1、参考c++primer P147