深蓝学院C++基础与深度解析笔记 第 4 章 表达式

第 4 章 表达式

一、表达式基础

A、表达式: 由一到多个操作数组成,可以求值并 ( 通常会 ) 返回求值结果:

#include <iostream>
int main(){
     int x;
     x = 3;
}
  • 最基本的表达式:变量、字面值
  • 通常来说,表达式会包含操作符(运算符), 且可以嵌套
  • 操作符的特性
    ● 接收几个操作数:一元、二元、三元 ?:
    ● 操作数的类型 - 类型转换
    ● 操作数是左值还是右值
    ● 结果的类型
    ● 结果是左值还是右值
    ● 优先级与结合性 (cpp-reference) ,可以通过小括号来改变运算顺序,和数学上一样,相同的优先级的结合性相同
    ● 操作符的重载 不改变接收操作数的个数、优先级与结合性
  • 操作数求值顺序的不确定性

最终的顺序:

括号 -> 优先级 -> 结合性

PS: 函数调用也是表达式:

#include<iostream>
void fun(int p12, int p2)
{
    std::cout<< p1 << ' ' << p2 << '\n';
}
int main(){
    int x=0;
    fun(x=x+1,x=x+1); 
}

函数参数计算顺序可能不同

B、左值和右值
传统的左值与右值划分

– 来源于 C 语言:左值可能放在等号左边;右值只能放在等号右边
– 在 C++ 中,左值也不一定能放在等号左边;右值也可能放在等号左边

● 所有的划分都是针对表达式的,不是针对对象或数值,针对表达式结果
– glvalue :泛左值:标识一个对象、位或函数
– prvalue :纯右值:用于初始化对象或作为操作数
– xvalue : 将亡值:表示其资源可以被重新使用,在内存销毁前把内容保留下来

decltype(实体/表达式)
在这里插入图片描述
● 左值与右值的转换
– 左值转换为右值( lvalue to rvalue conversion )
– 临时具体化( Temporary Materialization )
● 再论 decltype
– prvalue → type
– lvalue → type&
– xvalue → type&&

std::move()可以构造亡值

C、类型转换
一些操作符要求其操作数具有特定的类型,或者具有相同的类型,此时可能产生类型转换
1、 隐式类型转换

– 自动发生
– 实际上是一个(有限长度的)转型序列
– https://en.cppreference.com/w/cpp/language/implicit_conversion
– 并非所有类型之间都可以任意转换
数值提升:精度、内存空间提升;数值之间的转换可以导致精度缺失,更改值

2、显示类型转换
使用的时候小心谨慎些,容易出错,风险较大;尽量写长些,容易识别

– 显式引入的转换  可以使用括号和类型结合转换
– static_castconst_castdynamic_castreinterpret_cast
– C 形式的类型转换

关于类型转换的补充:

静态转换(Static Cast):
静态转换是最常用的类型转换方式之一,用于显式转换一种类型为另一种类型,但在转换时没有进行运行时检查。静态转换可以用于类层次结构中的上下转换(派生类向基类转换),以及非相关类型之间的转换。使用静态转换时,需要注意类型转换的安全性,因为它没有运行时检查。示例:

int x = 10;
double y = static_cast<double>(x);  // 将整数转换为浮点数

动态转换(Dynamic Cast):
动态转换用于在类层次结构中进行安全的上下转换(派生类向基类转换),并提供运行时类型检查。如果转换无效,即源指针指向的对象不是目标类型的一个有效派生类对象,动态转换将返回空指针(对于指针类型)或引发 std::bad_cast 异常(对于引用类型)。示例:

Base* basePtr = new Derived();  // 派生类指针赋值给基类指针
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);  // 动态转换
if (derivedPtr != nullptr) {
    // 转换成功,可以安全使用 derivedPtr
    derivedPtr->doSomething();
}

重新解释转换(Reinterpret Cast):
重新解释转换是一种较为低级别的转换方式,用于将一个指针或引用转换为不同类型的指针或引用,甚至可以将整数类型转换为指针类型或反之。它的行为比较危险,需要谨慎使用,因为它不会进行任何类型检查和转换。示例:

int x = 10;
double* ptr = reinterpret_cast<double*>(&x);  // 将整数指针转换为双精度浮点数指针

常量转换(Const Cast):
常量转换用于移除表达式的常量性(const)或将常量性添加到表达式。它主要用于处理函数重载或操作函数返回类型为常量的情况。常量转换不能用于修改实际的常量对象。示例:

const int x = 10;
int* ptr = const_cast<int*>(&x);  // 移除常量性以获取非常量指针
*ptr = 20;  // 修改通过常量指针获取的值

使用Boost将数字型对象的值转换为字符文本格式:boost::lexical_cast

在进行类型转换时,应谨慎考虑类型安全性和潜在的运行时错误

二、表达式详述

A、算术操作符
● 共分为三个优先级
– + , - (一元,正负号),可以让数组变成指针,类型提升
– * , / , % (%只接受整数)
– + , - (二元,加减号)
● 均为左结合的
● 通常来说,操作数与结果均为算数类型的右值;但加减法与一元 + 可接收指针
● 一元 + 操作符会产生 integral promotion
● 整数相除会产生整数,向 0 取整
● 求余只能接收整数类型操作数,结果符号与第一个操作数相同
● 满足 (m / n) * n + m % n == m

B、逻辑与关系操作符
● 关系操作符接收算术或指针类型操作数;逻辑操作符接收可转换为 bool 值的操作数
● 操作数与结果均为右值(结果类型为 bool )
● 除逻辑非外,其它操作符都是左结合的
● 逻辑与、逻辑或具有短路特性
● 逻辑与的优先级高于逻辑或,建议使用括号!
● 通常来说,不能将多个关系操作符串连 例子:c>b>a ×
● 不要写出 val == true 这样的代码
● Spaceship operator: <=>用于比较复杂的对象的对比(C++20)
– strong_ordering
– weak_ordering
– partial_ordering nan:not a number 非正常数字

c、位操作符
~:按位取反
在这里插入图片描述
在这里插入图片描述

接收右值,进行位运算,返回右值
● 除取反外,其它运算符均为左结合的
● 注意计算过程中可能会涉及到整形提升 integral promotion
● 注意这里** **
● 移位操作在一定情况下等价于乘(移位 :左移<< 1(乘2的1次)、右移>>1(除2)) 2 的幂,但速度更快
<<n : 乘2的n次 >>n : 除2的n次
● 注意整数的符号与位操作符的相关影响
– integral promotion 会根据整数的符号影响其结果
– 右移保持符号,但左移不能保证

D、赋值操作符
● 左操作数为可修改左值;右操作数为右值,可以转换为左操作数的类型
● 赋值操作符是右结合的:先处理右侧的
● 求值结果为左操作数
● 可以引入大括号(初始化列表)以防止收缩转换( narrowing conversion )
● 小心区分 = 与 ==
● 复合赋值运算符
交换x,y:
在这里插入图片描述

E、自增与自减运算符
● ++; –
● 分前缀与后缀两种情况

  • 操作数为左值;前缀时返回左值操作完之后的;后缀时返回操作之前的右值

● 建议使用前缀形式

F、其它操作符
● 成员访问操作符: . 与 ->
– -> 等价于 (*).
– . 的左操作数是左值(或右值),返回左值(或右值 xvalue ),和返回类型相同
– -> 的左操作数指针,返回左值
● 条件操作符
– 唯一的三元操作符: ?:,可以嵌套
在这里插入图片描述

– 接收一个可转换为 bool 的表达式与两个类型相同的表达式,只有一个表达式会被求值
– 如果表达式均是左值,那么就返回左值,否则返回右值
– 右结合,嵌套多层的?:会先转换成 单个的 ?:

G:其他操作符:
逗号操作符
– 确保操作数会被从左向右求值
– 求值结果为右操作数
– 左结合
●sizeof 操作符
– 操作数可以是一个类型(需要加括号)或一个表达式
并不会实际求值,而是返回相应的字节尺寸
● 其它操作符
– 域解析操作符 ::
– 函数调用操作符 ()
– 索引操作符 []
– 抛出异常操作符 throw
– …

在 C++17 中,可以确保 e1 会先于 e2 被求值
– e1[e2]
– e1.e2
– e1.e2
– e1→
e2
– e1<<e2
– e1>>e2
– e2 = e1 / e2 += e1 / e2 *= e1… (赋值及赋值相关的复合运算)
● new Type(e) 会确保 e 会在分配内存之后求值

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

甜橙の学习笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值