01表达式基础
定义:表达式由一到多个操作数组成,可以求值,通常会返回求值结果.
最基本的表达式:变量\字面值 int x; x+3; 3+2;
通常表达式包括操作符(运算符) :+ - * / .....
操作符
特性:
1.接受几个操作数 一元 ++x ; x++ 二元 1+1; 三元 if x>0? a: b (唯一的三元操作符)
2.转化操作数的类型 3+2.5 操作符+将3变为double
3.操作数是左值还是右值
4.结果是左值还是右值
5.优先级与结合性 优先级:3+2*5 结合性:默认左结合 可以通过括号改变 3+(2+5)
6.操作符的重载 ---只改变运算符的逻辑 不改变操作数的个数,优先级和结合性
操作数的求值顺序是不确定的
fun(int x,int y) { .....} int main() { int a; int b; fun(++a,++b) ++a,和++b执行顺序由底层硬件确定 使执行速度最快 运算效率最高 }
左值/右值
C语言:左值可能放在等号左边 右值只能放在等号右边 int x; x=3; 3=x(error)
C++:左值不一定放在等号左边,右值也可能放在等号左边 const int x=3; x=6 error 右值也可放在左边初始化
左右值的划分都是针对表达式的,不针对对象或数值
glvalue :泛左值 generalized ------确定一个对象,位域,或函数的表达式
int x; int y x=3; y=4; x y 泛左值 3,4纯右值 作为=的操作数
prvalue :纯右值 prue 作为某个运算符的操作数 初始化某个对象或者位域
---int x=9; 初始化
xvalue:将亡值 expiring 代表资源能够被重新使用的对象或者位域 ----std::move(x) 构造将亡值
Note:
左值转化为右值 int x=4; int y=x;
临时具体化
decltype:
prvalue------->type decltype(3) x; =>int x
lvalue---------->type & int x; decltype ( (x) ) y=x; =>int &y=x;
xvalue---------->type&& dacltype(std::move(x)) y=std::move(x); =>int &&y=std::move(x);
类型转换
一些操作符要求操作数具有特定的类型,或者相同的类型 此时可能产生类型转换
隐式类型转换
自动发生 3+0.5 "abcd"+4 error
显示类型转换: ----------------回应如会引入错误 不建议使用
static_cast ----编译期间完成
const_cast
dynamic_cast ----运行期间转换
reinterpret_cast 重解释
static_cast<>()
cout<<static_cast<double>(3)+0.9<<endl;
cout<<static_cast<double>("abcdef")+3; error
int x=3;
int y=4;
cout<<x/static_cast<double>(y)<<endl; ----0.75
cout<<static_cast<double>(x/y)<<endl; -----0
int *ptr;
void *v=ptr;
int *prt =v; error
int *ptr2=static_cast<int*>(v);
const_cast<>()
const int *ptr;
static_cast<int*>(ptr); error
const_cast<int*>(ptr);
reinterpret_cast<>() ------主要针对指针
int x=3;
double y=reinterpret_cast<double><x> error
int *ptr=&x;
double *ptr2=reinterpret_cast<double*>(ptr)
C语言类型的类型转换:
(double)3
(int)x
算术操作符
三个优先级:
一级: - + (一元) +x;
二级: * / %
三级: + - (二元)
7+*3
均为左结合 1+3-5
操作数和结果均为算术类型的右值 其中加减法与一元加可以接受指针
int a[3]={1,2,3}; int *ptr=a; ptr+1; ptr-1; end(a)-begin(a)
指针相减合法 指针相加不合法
一元+会产生类型提升 : short x=9; auto y=+x; y---int
整数相除会产生整数 向0取整 4/3=1 3/4=0 4/-3=-1
取余只能接受整数类型的操作数 结果符与第一个操作数相同
4%3=1
关系操作符
关系操作符 > < == != -------- 接受算术类型或者指针类型的操作数 ptr !=3 error类型不同
逻辑操作符! && || -------------接受可转化为bool值的操作数
操作数和结果均为纯右值 (结果类型为bool)
出逻辑非外,其他操作符均为左结合 !......右结合 再非
逻辑与 逻辑或 具有短路特性 a&&b a||b 只要a满足条件 不再判断b
逻辑与的优先级高于逻辑或 a&&b||c
通常 不能将多个关系运算符串联 a<b<c error
不要写val==true这样的代码
int a=9; if (a==true) true转化为1 if(a==1)才执行条件 {......} if(a) a=9 非0 执行条件 {....}
位操作符 >>右移 <<左移
接受右值 进行位运算 返回右值
出取反~外, 其他运算符都是左结合
计算过程可能设计整形提升
这里没有短路逻辑
移位操作符在一定情况下等价于乘 除 2 的幂 但是速度更快
整数的符号与位操作符相关 右移保持符号 左移不能保证符号
右移后,插入符号位 左移后补0 符号位可能移除
signed char x=3; 00000011 char一个字节 8位
cout<<(x<<1)<<endl; 左移一位 00000110 输出6
cout<<(x>>1)<<endl; 右移一位 00000001 输出1
signed char x=-4; 11111100
cout<<(x<<1)<<endl; 左移一位 11111000 输出-8
cout<<(x>>1)<<endl; 右移一位 11111110 输出-2
赋值操作符
左操作数为可以修改左值 右操作数为右值 可以转化为左操作数的类型
int x ; x=true ;
赋值操作符是右结合的 x=y=3;
求值结果是左操作数
可以引入大括号初始化列表
复合运算符 x*=3
int x=2; int y=3; x^=y^=x^=y 输出x=3 y=2;
自增与自减运算符
分前缀和后缀 ++ --
操作数为左值 ; 前缀返回左值 后缀返回右值
推荐使用前缀形式
int x=9;
x+=1; ------------>x=x+1;
x-=1; ----------->x=x-1;
x++:
返回运算前的值 内部有临时处理为 int temp=x; x=x+1; return temp;
----占用内存 效率低
++x:
返回运算后的值 x=x+1; return x;
int x=3;
int y;
y=x++;
cout<<x<<endl; ----->4
cout<<y<<endl; ------>3 返回运算前的值
y=++x;
cout<<x<<endl;--------->4
cout<<y<<endl;--------->4 返回运算后的值
int x=3;
++++x; ----------->5 右结合 前缀返回左值
x++++; error 后缀返回右值
其他操作符
成员访问符 . -> ->等价(*)
. 操作数是左值(右值) 返回左值 (右值)
-> 操作数是指针 返回左值
struct Str
{
int x;
};
int main()
{
Str a;
a.x;
Str*ptr=&a;
(*ptr).x;
ptr->x;
}
条件操作符: a?b:c 唯一的三元操作符
接受一个可转换为bool 的表达式 与两个类型相同的表达式, 其中满足条件只有一个表达式会被求值
如果表达式均是左值返回左值 否则返回右值
右结合
int x=2;
int y=3;
false? 1:x; 返回右值
true? y:x 返回左值
int score=100;
int res=(score>60)?1:(score>50)?0:-1; 右结合 先右边
逗号操作符:
确保操作数会从左向右求值 cout<<(2,3,4,5)<<endl; 5
求值结果是右操作数
左结合
sizeof操作符:
操作数是一个类型或者一个表达式 sizeof(int)
域解析操作符 ::
函数调用操作符 () fun()
索引操作符 X[ ] ptr[ ]
..........
持续更新.................