C++(4):表达式

news2025/1/19 11:25:31

表达式由一个或多个运算对象(operand)组成,对表达式求值将得到一个结果(result)。字面值和变量是最简单的表达式(expression),其结果就是字面值和变量的值。把一个运算符(operator)和一个或多个运算对象组合起来可以生成较复杂的表达式。

基础

概念

一元运算符:作用于一个运算对象的运算符是一元运算符,如取地址符(&)和解引用符(*);
二元运算符:作用于两个运算对象的运算符是二元运算符,如相等运算符(==)和乘法运算符(*)。
也有三元运算符,此外,函数调用也是一种特殊的运算符,

重载运算符:运算符作用于类类型的对象时,用户可以自行定义含义,为已存在的运算符赋予另一种含义。
运算对象的个数、运算符的优先级和结合律都是无法改变的。

左值:当一个对象被用作左值时,用的是对象的身份(在内存中的位置)。
右值:当一个对象被用作右值时,用的是对象的值(内容)。
在需要右值的地方可以用左值来代替,但是不能把右值当成左值(也就是位置)使用。
使用关键字decltype时,如果表达式的求值结果是左值,decltype作用于该表达式(不是变量)得到一个引用类型。

优先级与结合律

算术运算符满足左结合律:如果运算符优先级相同,按照从左向右的顺序组合运算对象。
括号无视优先级与结合律。

求值顺序

对于没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误并产生未定义的行为。

int i = 0;
cout << i << ++i << end;//未定义的

因为程序是未定义的,所以无法推断它的行为。可能输出 1 1 ,也有可能输出 0 1。

明确规定了求值顺序的运算对象:&& || ?: ,

处理复合表达式:
1.拿不准的时候最好用括号来强制让表达式的组合关系符合程序逻辑的要求。
2.如果改变了某个运算对象的值,在表达式的其他地方不要再使用这个运算对象。

算数运算符

在这里插入图片描述
**一元运算符的优先级最高,接下来是乘法和除法,优先级最低的是加法和减法。**上述都满足做结合律。
算术运算符都能作用于任意算术类型。算术运算符的运算对象和求值结果都是右值。

算术表达式有可能产生未定义的结果的原因:
1.数学性质本身:例如除数是0的情况;
2.源于计算机的特点:例如溢出,当计算的结果超出该类型所能表示的范围时就会产生溢出。

逻辑和关系运算符

关系运算符作用于算术类型或指针类型,逻辑运算符作用于任意能转换成布尔值的类型。逻辑运算符和关系运算符的返回值都是布尔类型。
在这里插入图片描述

赋值运算符

赋值满足右结合定律。
赋值运算优先级较低,低于关系运算符的优先级。

C++语言允许用赋值运算作为条件:if(i = j),这并不会出错,因此在写if(i == 1)时,尽量写为 if(1 == i),这样可以避免少写 = 而编译器不会报错。

复合赋值符与普通运算符唯一的区别是:使用复合运算符只求值一次,使用普通的运算符则求值两次。
这两次包括:一次是作为右边子表达式的一部分求值,另一次是作为赋值运算的左侧运算对象求值。

递增和递减运算符

递增和递减运算符有两种形式:前置版本和后置版本。

int i=0,j=0;
j = ++i;//j=1, i=1:前置版本得到递增之后的值
j = i++;//1 j= l, i=2:后置版本得到递增之前的值

这两种运算符必须作用于左值运算对象。前置版本将对象本身作为左值返回,后置版本则将对象原始值的副本作为右值返回。
前置版本的递增运算符避免了不必要的工作,它把值加1后直接返回改变了的运算对象。与之相比,后置版本需要将原始值存储下来以便于返回这个未修改的内容。如果我们不需要修改前的值,那么后置版本的操作就是一种浪费。

auto pbeg = v.begin();
//输出元素直至遇到第一个负值为止
while (pbeg != v.end() & & *beg >=0)
	cout<< *pbeg++ <<endl;//输出当前值并将pbeg向前移动一个元素

//等价于
while (pbeg != v.end() & & *beg >=0){
	cout<<*pbeg<<endl;
	++pbeg;
	}

后置递增运算符的优先级高于解引用运算符,因此*pbeg++等价于* (pbeg++)pbeg++pbeg的值加1,然后返回pbeg的初始值的副本作为其求值结果,此时解引用运算符的运算对象是pbeg未增加之前的值。最终,这条语句输出 pbeg开始时指向的那个元素,并将指针向前移动一个位置。

成员访问运算符

点运算符和箭头运算符都可以用于访问成员,其中,点运算符获取类对象的一个成员;箭头运算符与点运算符有关,表达式ptr->mem等价于(*ptr).mem

箭头运算符作用于一个指针类型的运算对象,结果是一个左值。点运算符分成两种情况:如果成员所属的对象是左值,那么结果是左值;反之,如果成员所属的对象是右值,那么结果是右值。

条件运算符

cond ? expr1 : expr2;

条件运算符的执行过程是:首先求cond的值,如果条件为真对exprl求值并返回该值,否则对expr2求值并返回该值。
条件运算符的优先级非常低,通常都要加括号。

位运算符

位运算符作用于整数类型的运算对象,并把运算对象看成是二进制位的集合。
在这里插入图片描述
一般来说,如果运算对象是“小整型”,则它的值会被自动提升成较大的整数类型。运算对象可以是带符号的,也可以是无符号的。

移位运算符

左移运算符(<<)在右侧插入值为0的二进制位。右移运算符(>>)的行为则依赖于其左侧运算对象的类型:如果该运算对象是无符号类型,在左侧插入值为0的二进制位;如果该运算对象是带符号类型,在左侧插入符号位的副本或值为0的二进制位。左移操作处理带符号值是一种未定义的行为。
在这里插入图片描述

sizeof 运算符

sizeof运算符返回一条表达式或一个类型名字所占的字节数。通常有两种形式:sizeof (type)sizeof expr。在第二种形式中,sizeof返回的是表达式结果类型的大小。

  • 对引用类型执行sizeof运算得到被引用对象所占空间的大小。
  • 对指针执行sizeof运算得到指针本身所占空间的大小。
  • 对解引用指针执行sizeof运算得到指针指向的对象所占空间的大小,指针不需有效。
  • 对数组执行sizeof运算得到整个数组所占空间的大小,等价于对数组中所有的元素各执行一次sizeof运算并将所得结果求和。注意,sizeof运算不会把数组转换成指针来处理。
  • 对string对象或vector对象执行sizeof运算*只返回该类型固定部分的大小,*不会计算对象中的元素占用了多少空间。

逗号运算符

逗号运算符(comma operator)含有两个运算对象,按照从左向右的顺序依次求值。
对于逗号运算符来说,首先对左侧的表达式求值,然后将求值结果丢弃掉。逗号运算符真正的结果是右侧表达式的值。

类型转换

隐式转换:自动执行,无须程序员介入。算术类型之间的隐式转换被设计得尽可能避免损失精度。
何时发生隐式类型转换:

  • 在大多数表达式中,比int类型小的整型值首先提升为较大的整数类型。
  • 在条件中,非布尔值转换成布尔类型。
  • 初始化过程中,初始值转换成变量的类型;在赋值语句中,右侧运算对象转换成左侧运算对象的类型。
  • 如果算术运算或关系运算的运算对象有多种类型,需要转换成同一种类型。
  • 函数调用时也会发生类型转换。

算数转换

**算术转换(arithmetic conversion)**的含义是把一种算术类型转换成另外一种算术类型。

如果某个运算符的运算对象类型不一致,这些运算对象将转换成同一种类型。
当表达式中既有浮点类型也有整数类型时,整数值将转换成相应的浮点类型。

如果一个运算对象是无符号类型、另外一个运算对象是带符号类型:
1.其中的无符号类型不小于带符号类型,那么带符号的运算对象转换成无符号的;
2.其中带符号类型大于无符号类型,此时转换的结果依赖于机器。

其他隐式类型转换

数组转换成指针:在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针。

int ia[10];//含有10个整数的数组
int* ip = ia;//ia转换成指向数组首元素的指针

指针的转换: 0 或 nullptr 都能转换成任意指针类型。指向非常量的指针能转换成 void*。指向所有对象的指针都能转换成 const void*。
转换成布尔类型:存在一种从算术类型或指针类型向布尔类型自动转换的机制。

char *cp =get_string O);
if (cp)/* ...*/	//如果指针cp不是0,条件为真
while (*cp)/*...*/	//如果*cp不是空字符,条件为真

转换成常量:允许将指向非常量类型的指针转换成指向相应的常量类型的指针。(引用也一样)

int i;
const int &j = i;//非常量转换成const int的引用
const int *p = &i;//非常量的地址转换成const的地址
int &r=j, *g = p;//错误:不允许const转换成非常量

类类型定义的转换:类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的转换。

string s, t= "a value";//字符串字面值转换成string类型
while (cin >>s)//while的条件部分把cin转换成布尔值

显示转换

强制类型转换:

cast-name<type>(expression);

其中,type是转换的目标类型而expression是要转换的值。如果type是引用类型,则结果是左值。cast-name指定了执行的是哪种转换。
cast-name是 static _cast 、 dynamic_cast , const_cast 和 reinterpret_cast 中的一种。

static_cast

任何具有明确定义的类型转换,只要不包含底层const,都可以使用static cast。

double slope = static_cast<double>(j)/i; //将 j 转换成 double 以便执行浮点数除法

当需要把一个较大的算术类型赋值给较小的类型时,static_cast非常有用。此时,强制类型转换告诉程序的读者和编译器:我们知道并且不在乎潜在的精度损失。
如果编译器发现一个较大的算术类型试图赋值给较小的类型,就会给出警告信息;但是当我们执行了显式的类型转换后,警告信息就会被关闭了。

const_cast

const cast只能改变运算对象的底层const。
只有 const_cast 能改变表达式的常量属性,使用其他形式的命名强制类型转换改变表达式的常量属性都将引发编译器错误。同样的,也不能用 const_cast 改变表达式的类型:

const char *cp;
char *q = static_cast<char*>(cp);//错误:static_cast不能转换掉const性质
static_cast<string>(cp);//正确:字符串字面值转换成string类型
const_cast<string>(cp);//错误:const_cast只改变常量属性
reinterpret_cast

reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释。风险高,尽量不用。

旧式的强制类型转换

type (expr);//函数形式的强制类型转换
(type) expr;//C语言风格的强制类型转换

与命名的强制类型转换相比,旧式的强制类型转换从表现形式上来说不那么清晰明了,容易被看漏,所以一旦转换过程出现问题,追踪起来也更加困难。

重要术语

  1. 强制类型转换(cast) 一种显式的类型转换。
  2. 整型提升(integral promotion) 把一种较小的整数类型转换成与之最接近的较大整数类型的过程。不论是否真的需要,小整数类型(即 short、 char等)总是会得到提升。
  3. 短路求值(short-circuit evaluation) 是一个专有名词,描述逻辑与运算符和逻辑或运算符的执行过程。如果根据运算符的第一个运算对象就能确定整个表达式的结果,求值终止,此时第二个运算对象将不会被求值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/556385.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

倒挂的解决方案你现在是一位计算机专家,来聊一聊:“美国的火星探测器Mars Path-finder 就是因为优先级倒挂而出现故障的故事”

目录 倒挂的解决方案 你现在是一位计算机专家&#xff0c;来聊一聊&#xff1a;“美国的火星探测器Mars Path-finder 就是因为优先级倒挂而出现故障的故事” ●使用中断禁止 具体证明请参阅Liu和Kayland于1973年发表的论文。 ● 因时序或外部中断或进程挂起而导致操作系统获…

数据结构-关键路径-理论

1.AOE-网 与AOV-网相对应的是AOE-网&#xff08;Activity On Netword&#xff09;&#xff0c;即以边表示活动的网。AOE-网是带权的有向无环图&#xff0c;其中&#xff0c;定点表示时间&#xff0c;弧表示活动&#xff0c;权表示活动持续的时间。通常AOE-网可用来估算工程的完…

Base64字符串从前台传到后台以后,“+”加号消失

记录一下问题&#xff1a; 使用 encodeURI(str) 对字符串进行加密的时候&#xff0c;后端解密会丢失 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content&…

第一章.机器学习的基础概念

第一章.机器学习的基础概念 1.1 机器学习的基础概念 1.机器学的概念&#xff1a; 机器学习就是机器从数据中总结经验。从数据中找出某种规律或者模型&#xff0c;并用他来解决某种实际问题。 2.机器学习的应用场景 1).事物本身存在某种潜在规律 2).某些问题难以使用普通编程…

two-stage目标检测算法

R-CNN 现在&#xff0c;将目光穿越回2012年&#xff0c;hinton刚刚提出alexnet的时代。 此时&#xff0c;该如何审视目标检测任务&#xff1f; 当时的目标检测采用的是滑动窗口手动特征分类器的思路。 该方法的弱点包括 速度慢 精度差 精度差的问题是由手工特征造成的&am…

【VS安装记录】Visual Studio 2022安装教程(超详细)

大家好&#xff0c;我是雷工&#xff01; 由于更换了电脑&#xff0c;很多软件需要重新安装&#xff0c;为了方便学习C#&#xff0c;今天有时间安装下Visual Studio 2022&#xff0c;顺便记录安装过程。 1、从官网下载并解压软件压缩包&#xff0c;然后打开文件夹。 2、双击…

切比雪夫不等式,大数定律及极限定理。

一.切比雪夫不等式 1.定理 若随机变量X的期望EX和方差DX存在,则对任意ε > 0,有   P{ |X - EX| > ε } < DX/ε2 或 P{ |X - EX| < ε } > 1 - DX/ε2 2.解析定理 ①该定理对 X 服从什么分布不做要求&#xff0c;仅EX DX存在即可。 ②“| |” 由于X某次…

linux kernel pwn 基础知识

基础知识 内核概述 内核架构 通常来说我们可以把内核架构分为两种&#xff1a;宏内核和微内核&#xff0c;现在还有一种内核是混合了宏内核与微内核的特性&#xff0c;称为混合内核。 宏内核&#xff08;Monolithic kernel&#xff09;&#xff0c;也译为集成式内核、单体…

网络原理——基础概念(端口号、分层、封装和复用)、各层协议(TCP/IP协议)(详细图解)

目录 一、基础概念 1、 IP地址 &#xff08;1&#xff09;点分十进制 2、端口号 3、协议 &#xff08;1&#xff09;协议的 组成部分 &#xff08;2&#xff09; 协议的 作用 4、五元组 5、协议分层 &#xff08;1&#xff09;分层的 好处 &#xff08;2&#xff0…

Overleaf中Latex问题——控制文本分两列显示(分栏布局)

文章目录 需求描述相关介绍实现代码实现效果参考和总结 需求描述 要写论文&#xff0c;需要分两列进行显示文本。但是默认都是单列展示&#xff0c;并且自动换行。 需要实现一下的效果 相关介绍 在$LaTeX 中&#xff0c;你可以使用 中&#xff0c;你可以使用 中&#xff0c…

Tokenview上线BRC-20浏览器,支持Ordinals API数据服务

5月20日&#xff0c;Tokenview团队宣布正式推出BRC-20代币浏览器&#xff0c;同时支持BTC Ordinals API数据服务。作为通用多链区块链浏览器&#xff0c;Tokenview以最快的速度推出了BRC-20浏览器&#xff0c;Ordinals API旨在为所有面向比特币的普通用户和开发者提供数据支持&…

追寻篮球梦想 点燃希望之光 2023年海彼特全国幼儿篮球联赛·总决赛圆满落幕

5月21日&#xff0c;由北京海彼特教育科技院主办的“2023年海彼特全国幼儿篮球联赛总决赛”。在河北体育馆隆重举行&#xff0c;精彩的比赛效果使体育馆顿时成为幼儿篮球界最高端、大气的舞台。 本次盛会联合举办方有&#xff1a; 河北体育馆 亚洲少儿体育协会 北京海彼特文…

组件123456789

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

G企孵化-千趣生活项目,10年互联网经验专业策划商业模式

G企孵化-千趣生活项目&#xff0c;10年互联网经验专业策划商业模式 背景&#xff1a;现在许许多多的项目&#xff0c;首先对外呼吁的口号就是“上市”但真正能做到上市的企业&#xff0c;确实没有几个&#xff0c;10年互联网经验的微三云胡佳东&#xff0c;给大家详细聊聊&…

【卡尔曼滤波的学习,以及一些理解】

卡尔曼滤波的一些理解 优秀的博客推荐直观理解卡尔曼滤波核心算法举个例子 最近两个多月在实习&#xff0c;做的是GPS定位相关的一些工作&#xff0c;同时也简单做了一下组合导航。卡尔曼滤波是组合不同传感器比较核心的算法&#xff0c;应用也比较广泛&#xff0c;也有很多文章…

电子数据保全及数据恢复

目录 一.创建虚拟磁盘 系统操作 1.创建虚拟磁盘文件 2.完成低级格式化——分区——高级格式化 3.虚拟磁盘创建完成 用winhex做 2. 镜像&#xff1a; 克隆&#xff1a; 计算分区的hash值&#xff1a; 二.FAT32文件系统 1.认识FAT32文件系统 三.NTFS文件系统 认识NTFS文…

数字信号处理5

好长时间没有更新了&#xff0c;一是这段时间事情比较多&#xff0c;另外一个&#xff0c;我觉得抄书其实意义不大&#xff0c;不如先看书&#xff0c;一个章节看完之后&#xff0c;再写&#xff0c;那样子的话&#xff0c;会效果更好一些&#xff0c;所以我就花了一段时间去把…

chatgpt赋能Python-python_chia

简介&#xff1a;什么是Python Chia&#xff1f; Python Chia是一种加密货币&#xff0c;它的挖矿过程使用Python编程语言。Python Chia是开源的&#xff0c;任何人都可以参与挖矿。 Chia使用绿色挖矿的方式&#xff0c;这意味着Chia的挖矿过程对环境没有任何负面影响。此外&…

typeScript开发

typeScript开发 1.TypeScript简介2.TypeScript 安装3.TypeScript 基础语法3.TypeScript 基础类型4.TypeScript 变量声明5.TypeScript 运算符6.TypeScript 条件语句7.TypeScript 循环8.TypeScript 函数9.TypeScript Number10.TypeScript String&#xff08;字符串&#xff09;11…

使用github CICD 简单部署vue项目

1.首先先创建一个github访问地址&#xff0c;关于Github Pages的域名访问地址&#xff0c;在github上新建一个以域名为名称的仓库即可&#xff0c;一般都是githubname.github.io 2.首先创建vue项目&#xff0c;这里我就使用自己写的前端项目脚手架来创建vue项目 这里顺便把图标…