当前位置: 首页 > news >正文

C++中的表达式

文章目录

  • 算数操作符
  • 位操作符
    • bitset对象或整型值的使用
    • 将位移操作符用作IO
  • 赋值操作符
    • 赋值操作符的右结合性
    • 赋值操作具有低优先级
  • 自增和自减操作符
  • 条件操作符
  • sizeof操作符
  • 优先级
  • new和delete表达式
  • 类型转换
    • 何时发生隐式转换
    • 显示转换
    • 旧式强制类型转换

C++中的表达式由一个或多个操作数通过操作符组合而成。最简单的表达式仅包含一个字面值常量或变量。每个表达式都会产生一个结果。如果表达式中没有操作符,则其计算结果就是操作数本身。除了特殊的用法外,表达式的结果是 右值,可以读取该结果值,但是不允许对它进行赋值。

算数操作符

在这里插入图片描述
一元操作符优先级最高,其次时乘除,最后是加减。其中求模操作中值得注意得是:

-21 % -8; //-5,当两个数都是负数,求模(取余)操作的为负数或0
21 % -5; //1或-4,当两个操作数只有一个负数时,结果值得符号可依据分母或分子得符号而定,这两种操作得结果取决于机器

在这里插入图片描述

expr1 && expr2;
expr3 || expr4;

逻辑与和逻辑或总是先计算左操作数,只有在左操作数无法确定逻辑表达式得结果时,才会计算右操作数。这种求值策略被称为“短路求值”。

位操作符

在这里插入图片描述
位操作符操作的整数类型可以是有符号的也可以是无符号的。如果操作数为负数,则位操作符如何处理操作数的符号位依赖于机器。由于系统不能确保如何处理操作数的符号位,所以建议使用unsigned整型操作数。

bitset对象或整型值的使用

bitset<30> bitset_quizl;
unsigned long int_quizl = 0;//操作第27位
bitset_quizl.set(27); // set置为1,reset置为0
int_quizl |= 1UL << 27; // 置1
int_quizl &= ~(1UL << 27); // 置0

一般而言,标准库提供的bitset操作更加直接、更容易阅读和书写、正确的使用的可能性更高。而且bitset对象的大小不受unsigned的位数限制。

将位移操作符用作IO

输入输出标准库分别重载了位操作符>>和<<用于输入和输出。重载的操作符和内置版本有相同的优先级和结合性。优先级比算数操作符低,但比关系操作符、赋值操作符和条件操作符高。

cout << 42 + 10;
cout << (10 < 42);
cout << 10 < 42; // ❌

赋值操作符

赋值操作符的右结合性

int ival, jval; 
ival = jval = 0;

值得注意的是,操作对象必须具有相同的类型,或者具有可转换位同一类型的数据类型。

赋值操作具有低优先级

int i = get_value();
while(i != 42)
{// do something();i = get_value();
}
// 更简洁的写法
while((i = get_value()) != 42)
{// do something;
}

第二种写法更加简洁和清晰。值得注意的是在赋值操作中的圆括号是必须的,因为赋值操作符的优先级低于不等操作符。

自增和自减操作符

  • 后置操作符返回未加1的值
int i = 0, j;
j = ++i; // i = 1, j = 2;
j = i++; // i = 2, j = 1;

前置操作返回自增之后的结果,后置操作返回自增之前的结果。只有在必要时才使用后置操作。因为其在实现的过程中回产生一个临时对象,从而增加时间开销。

  • 在单个表达式中组合使用解引用和自增操作
vector<int>::iterator iter = ivec.begin();
while(iter != ivec.end())
{cout << *iter++ << endl;
}

自增操作的优先级高于解引用,因此先自增,在解引用。后置自增返回自增之前的值,因此解引用可以从0开始。

条件操作符

  • 嵌套条件操作符
int i = 10, j = 20, k = 40;
int max = i > j? i > k? i : k: j > k? j : k;
  • 在输出表达式中使用条件操作符
cout << (i < j ? i : j);
cout << i < j ? i : j; // ❌

条件表达式的优先级很低,想要不出错,最好用圆括号把表达式括起来。

sizeof操作符

sizeof表达式的结果是编译时常量,通常有以下三种语法形式:

  • sizeof(type name);
  • sizeof(expr);
  • sizeof expr;
// 以下三种得到都是Sales_item的大小
Sales_item item, *p;
sizeof(Sales_item);
sizeof item;
sizeof *p; 

优先级

在这里插入图片描述
在这里插入图片描述
上表按照优先级顺序列出了C++的全部操作符。该表不同优先级的操作符划分到不同段中,每段内各个操作符优先级相同,且都高于后面各段中的操作符。值得注意的后自增操作优先级比前自增操作的优先级更高

new和delete表达式

  • 初始化
\\ 动态创建类类型,回自动调用默认构造函数
string *s = new string;
\\ 内置类型,不会自动初始化
int *pi = new int;
\\ 可通过在类型名后加(),进行值初始化
int *pi = new int();
  • new分配内存失败
    分配失败系统将抛出名为bad_alloc的异常。
  • 在delete之后,重设指针的值
delete p;
p = nullptr;

在delete动态分配的之后,p变成没有意义。在很多机器之上,尽管p没有意义,但仍存放了它之前所指向地址的值,然后p所指向的内存已经被释放,因此p不在有效。
删除指针之后,该指针变成垂悬指针。为了防止出错,在删除指针之后,立即将其置为0。

类型转换

由编译器自动进行类型转换称之为隐式类型转换。

何时发生隐式转换

在下列情况下,将发生隐式类型转换:

  • 混合类型的表达式中,其操作数转化为相同的类型
int ival;
double dval;
ival >= dval; // ival转化为double,一般向精度更大的类型进行转换
  • 用作条件表达式被转换为bool类型
int ival;
if(ival)
while()
&&, ||, !, ?:等等
  • 用一表达式初始化或赋值某个变量,该表达式结果转化为该变量类型。

显示转换

显示转换也称为强制类型转换(cast),包括static_cast、dynamic_cast、const_cast和reinterpret_cast。

  • 何时需要强制类型转换
double dval;
int ival;
ival *= dval; // ival * dval,ival先转double,ival = ival * dval,赋值操作结果转int
ival *= static_cast<int>(dval); // 有效减少隐式转换的次数
  • 使用场景
// dynamic_cast,支持运行时识别指针或引用所指向的对象
// const_cast,添加移除const属性,const_cast<new_type>(expression)
// static_cast,编译器隐式转换的任何类型都可以由static_cast显示完成
// reinterpret_cast,通常为操作数的位模式提供低层次的重新编译。本质上依赖于机器。
//为了安全的使用,要求程序员完全理解所设计的类型,以及编译器实现强制类型转换的细节。
// 转换后的类型通常与原类型完全不相关,用于底层操作,转换为完全不相关的类型,如指针与整数之间的转换。
//这种转换是危险的,可能会导致未定义行为,特别是在内存布局不一致的情况下
int *ip;
char *pc = reinterpret_cast<char*>(ip); // 程序员必须永远记着pc所指向的真实对象是int型,而非字符数组。任何假设pc是字符指针的应用,可能带来未知的错误。

旧式强制类型转换

在引入相知类型转换操作符之前,显示强制类型转换用圆括号实现。

// 以下两种写法都可
char *pc = (char*) ip;
char *pc = char*(ip);

旧式强制类型转换具有和static_cast、const_cast以及reinterpret_cast一样的行为。在合法使用前两者的场景中,提供了与各自对应命名强制转换一样的功能。如果这两种转换均不合法,则执行reinterpret_cast的功能。
支持旧式强制类型转换是为了对保持老程序的兼容性,一般建议使用命名强制转换。


http://www.mrgr.cn/news/83204.html

相关文章:

  • Unity2D初级背包设计中篇 MVC分层撰写(万字详解)
  • 【C++多线程编程:六种锁】
  • 基于海思soc的智能产品开发(camera sensor的两种接口)
  • 前端开发【插件】moment 基本使用详解【日期】
  • Windows 下Mamba2 / Vim / Vmamba 环境安装问题记录及解决方法终极版(无需绕过triton)
  • 云计算在医疗行业的应用
  • 高性能网络模式:Reactor 和 Proactor
  • Linux标准IOday3
  • yum换源
  • Spring——自动装配
  • 【python基础——异常BUG】
  • redis:安装部署、升级以及失败回退
  • 【算法】八大排序算法
  • UI自动化测试框架playwright--初级入门
  • 音视频入门基础:MPEG2-PS专题(5)——FFmpeg源码中,解析PS流中的PES流的实现
  • K-means算法在无监督学习中的应用
  • 第四、五章图论和网络爬虫+网络搜索
  • python虚拟环境的使用
  • C# 对象和类型(结构)
  • ArrayList和HashMap区别
  • 2025新年源码免费送
  • 【JavaEE进阶】获取Cookie/Session
  • 强化学习入门
  • 【C++】16.stack和queue的使用
  • 【TI毫米波雷达】DCA1000不使用mmWave Studio的数据采集方法,以及自动化实时数据采集
  • UI自动化测试保姆级教程--pytest详解(精简易懂)