引入
表达式由一个或多个操作数组成,可以求值,并返回值的结果。
操作符只能接受某些类型的操作数,并不能接受全部类型的操作数。
一个操作符,可以接受左值或者右值。但是有些情况下,操作符只能接受左值
也有从右往左算的,比如++a. --b等,~ ! *a,&a 等等。
可以通过小括号,改变优先级顺序。
相同优先级的操作符,要么是左到右,要么是右到左。必须要这样的rules。
左值与右值
左值left-value和右值right-value是针对赋值语句的等号来说的。
上述是c语言的定义。
但是到了cpp,就称为:左值也不一定放在=左边,右值也可能放在=左边。
所有的划分,都是针对表达式的,不是针对对象或者数值的。
glvalue-泛左值:是一个表达式,这个表达式的求值结果可以确定一个对象、位域(某个字节的具体位置,一个bit),函数。
prvalue-纯右值:与glvalue对应,作为某个运算符的操作数,或者void表达式(一个void的函数)
3是字面值,不是一个对象,所以在这里是一个纯右值。老师这里说3在底层没有一个块内存对应它。但是我的理解是,3是有开辟内存的,只是这个内存只存了字面值,而没有对象。或者指针等。
xvalue-亡值:将亡值。代表其资源能够被重新使用的泛左值。
左值会产生T的引用。
T&&右值引用,上面我写错了。
类型转换
隐式类型转换
显式类型转换
int main()
{
3 + 0.5;
static_cast<double>(3) + 0.5; // int 3 转换成 double 类型
}
int main()
{
cout << (3 / 4) << endl; // 0
cout << (3 / 4.0) << endl; // 0/75
int x = 3;
int y = 4;
cout << (x / y) << endl; // 0
cout << (x / static_cast<double>(y)) << endl; // 0.75
}
dynamic_cast是唯一一个在运行期进行的转换。
static_cast在编译器就弄好了,所以效率更高,但是运行时,可能出错。
const_cast,会改变变量的常量型。
int main()
{
const int x = 3;
cout << static_cast<int>(x) << endl; // const int转成int时可以的,但是const int*不行
const int* y;
cout << static_cast<int*>(y) << endl; // static_cast from 'const int *' to 'int *' is not allowed
const int* z;
cout << const_cast<int*>(z) << endl; // 0x0, 使用const_cast是可以的
}
int main()
{
int x = 3;
const int& ref = x;
int& ref2 = const_cast<int&>(ref); // 用const_cast对ref去const
ref2 = 4;
cout << ref << endl; // 4
cout << ref2 << endl; // 4
cout << x << endl; // 4
}
int main()
{
const int x = 3; // 加了一个const
const int& ref = x;
int& ref2 = const_cast<int&>(ref);
ref2 = 4;
cout << ref << endl; // 4
cout << ref2 << endl; // 4
cout << x << endl; // 3 编译器不同,输出不同,不做保证,行为不确定
}
reinterpret cast
强行将原内存重新解释。
ptr2每次的值都不同,因为将一个int强行解释成double。另外int和double站的内存不同。
c类型的转换
显示类型的转换都是有风险的。尽量不要用。