[c++primer][05]表达式
5.1 算术操作符
算术类型具有有限的长度,要注意计算后溢出的现象
求模操作(%)的操作数必须为整型
当两个操作数只有一个为负数时,操作结果的正负取决于机器。
5.2 关系操作符和逻辑操作符
关系、逻辑操作符使用算术或指针类型的操作数,并返回bool类型的值。
短路求值
&& 和 || 总是在仅靠左操作数无法确定结果时,再计算右操作数。
5.3 位操作符
用于整型和bitset类型
输入输出标准库(IO library)分别重载了位操作符>>和<<用于输入和输出,IO操作符为左结合
5.4 赋值操作符
数组名是不可修改的左值,因此不可用作赋值操作符号的目标。
一个优化的例子
谨防混淆
if(i == 42) 特别容易疏忽而写成 if(i=42),这类错误很难发现,故写作if (42 == i) 为好,可以及时报错
符合赋值操作符
a op= b; op=可以是以下10个操作符
5.5 自增和自减操作符
只有在必要时才使用后置操作符
前置操作只需加1(或减1)后返回结果即可;后置操作则必须先保存操作数原来的值,一遍返回未加1(或减1)之前的值作为操作的结果,对于复杂迭代器类型,这种额外工作可能会花费更大代价。
5.6 箭头操作符
获取所指向的类对象的成员
5.7 条件操作符
避免深度嵌套
==>
5.8 sizeof操作符
sizeof ( expr )
将sizeof用于expr时,并没有计算表达式expr的值。若sizeof *p,并没有对p做解引用
对指针做sizeof操作返回存放指针所需内存大小;对数组做sizeof操作等效于将对其元素类型做sizeof操作的结果乘上数组元素的个数
5.9 逗号操作符
从左向右计算,返回最右边表达式的值
5.10 复合表达式的求值
优先级:子表达式分组
粗略地,算术>移位>关系>逻辑>条件>赋值
结合性:操作符分组
右结合有,! ~ ++ -- + - * & (类型) sizeof new delete ?: 赋值与复合赋值
求值顺序:
除了&&、||、(?:)、(,)规定了计算顺序,其它操作符都未指定操作数的求值顺序。
一个表达式里,不要在两个或更多的子表达式中对同一对象做自增或自减操作。
5.11 new和delete表达式
不提供显式初始化时,动态创建的对象与在函数内定义的变量初始化规则相同。
在类型名后面使用一对空圆括号,对动态创建的对象做值初始化。
对内置类型或没有定义默认构造函数的类型,采用不同初始化式有显著区别
删除0值指针是安全的,但没有任何意义;在delete指针之后,指针变成悬垂指针,应当立即将指针置0。
三种与动态内存分配相关的错误:
1)删除指向动态分配内存的指针失败,无法回收,造成内存泄露;
2)读写已删除的对象。
3)对同一个内存空间使用两次delete表达式。
5.12 类型转换
1、隐式转换
何时发生隐式转换
1)混合类型表达式中,操作数被转换为相同类型
2)用作条件的表达式被转换为 bool类型
3)用表达式对某个变量初始化(或赋值),该表达式转换为该变量类型
算术转换
整型提升:对于所有比int小的整型,包括char、signed char、unsigned char、short和unsigned short,都会被提升为int,否则就会提升为unsigned int
无符号数所定义的转换规则需保护操作数的精度
不将数组名转换为指针的情况:数组名用作取地址操作符的操作数或sizeof操作符的操作数,或数组对数组的引用进行初始化时
2、显式转换(强制类型转换)
cast-name<type> ( expression ); //type为目标类型,expression是被强制转换的值
强制转换的类型指定了在expression上执行某种特定类型的转换。
dynamic_cast
运行时识别指针或引用所指向的对象
const_cast
添加或删除const特性
static_cast
编译器隐式执行的转换或编译器不提供自动转换
reinterpret_cast
为操作数的位模式提供较低层次的重新解释,依赖于机器。
强制类型转换关闭或挂起了正常的类型检查,强烈建议程序员避免使用强制类型转换。
3、旧式强制类型转换
在引入命名的强制类型转换之前,显式强制转换用圆括号将类型括起来实现。
附:C++操作符优先级
操作符的优先级 |
|||
操作符及其结合性 |
功能 |
用法 |
|
L L L |
:: :: :: |
全局作用域 类作用域 名字空间作用域 |
:: name calss :: name namespace :: name |
L L L L L |
. -> [] () () |
成员选择 成员选择 下标 函数调用 类型构造 |
object.member pointer->member variable[expr] name(expr_list) type(expr_list) |
R R R R R |
++ -- Typeid Typeid 显式强制类型转换 |
后自增操作 后自减操作 类型ID 运行时类型ID 类型转换 |
Lvalue++ Lvalue— Typeid(type) Typeid(expr) Cast_name<type>(expr) |
R R R R R R R R R R R R R R |
Sizeof Sizeof ++ -- ~ ! - + * & () New Delete Delete [] |
对象的大小 类型的大小 前自增操作 前自减操作 位求反 逻辑非 一元负号 一元正号 解引用 取地址 类型转换 创建对象 释放对象 释放数组 |
Sizeof expr Sizeof(type) ++lvalue --lvalue ~expr !expr -expr +expr *expr &expr (type)expr New type Delete expr Delete []expr |
L L |
->* .* |
指向成员操作的指针 指向成员操作的指针 |
Ptr->*ptr_to_member Obj.*ptr_to_member |
L L L |
* / % |
乘法 除法 求模(求余) |
Expr * expr Expr / expr Expr % expr |
L L |
+ - |
加法 减法 |
Expr + expr Expr - expr |
L L |
<< >> |
位左移 位右移 |
Expr << expr Expr >> expr |
L L L L |
< <= > >= |
小于 小于等于 大于 大于等于 |
Expr < expr Expr <= expr Expr > expr Expr >= expr |
L L |
== != |
相等 不等 |
Expr == expr Expr != expr |
L |
& |
位与 |
Expr & expr |
L |
^ |
位异或 |
Expr ^ expr |
L |
| |
位或 |
Expr | expr |
L |
&& |
逻辑与 |
Expr && expr |
L |
|| |
逻辑或 |
Expr || expr |
R |
? : |
条件操作 |
Expr ? expr : expr |
R R R R R |
= *= , /= , %=, += , -=, <<= , >>= , &= , |= , ^= |
赋值操作 复合赋值操作 |
Lvalue = expr Lvalue += expr等等 |
R |
Throw |
抛出异常 |
Throw expr |
L |
, |
逗号 |
Expr, expr |
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· golang自带的死锁检测并非银弹
· 2024年终总结:5000 Star,10w 下载量,这是我交出的开源答卷
· 一个适用于 .NET 的开源整洁架构项目模板
· AI Editor 真的被惊到了
· API 风格选对了,文档写好了,项目就成功了一半!
· 【开源】C#上位机必备高效数据转换助手