C++ Primer 第四版读书笔记(四)之表达式

表达式由一个或多个操作数通过操作符组合而成。最简单的表达式仅包含一个字面值常量或变量。较复杂的表达式则由操作符以及一个或多个操作数构成。

每个表达式都会产生一个结果。如果表达式中没有操作符,则其结果就是操作数本身的值。当一个对象用在需要使用其值的地方,则计算该对象的值。

操作符的含义——该操作符执行什么操作以及操作结果的类型——取决于操作数的类型。

C++提供了一元操作符和二元操作符两种操作符。作用在一个操作数上的操作符称为一元操作符。如曲地址符(&)和解引用操作符(*);而二元操作符则作用于两个操作数上,如加法操作符(+)和减法操作符(-)。

一、算术操作符

当只有一个操作数为负数时,求模操作结果值的符号可依据分子(被除数)或分母(除数)的符号而定。如果求模的结果随分子的符号,则除出来的值想零一侧取整;如果求模与分母的的符号匹配,则除出来的值向负无穷一侧取整。

二、关系操作符和逻辑操作符

关系操作符和逻辑操作符
操作符 功能
! 逻辑非

<

<=

>

>=

小于

小于等于

大于

大于等于


==

!=

等于

不等

&& 逻辑与
|| 逻辑或

2.1 逻辑与、逻辑或操作符

仅当逻辑与(&&)操作符的两个操作数都为true,其结果才得true。

对于逻辑或(||)操作符,只要两个操作数之一为true,它的值就为true。

注:逻辑与和逻辑或操作符总是先计算做操作数,然后再计算其右操作数。只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数。我们常常称这种求值策略为“短路求值”。

2.2 不应该串接使用关系操作符

三、位操作符

位操作符使用整型的操作数。位操作符将其整型操作数视为二进制位的集合,为每一位提供检验和设置的功能。

位操作符
操作符 功能
~ 位求反
<<

>>

左移

右移

& 位与
^ 位异或
| 位或

位操作符操纵的整数的类型可以是有符号的也可以是无符号的。如果 操作数为负数,则位操作符如何处理其操作数的符号位依赖于机器。于是它们的应用可能不同:在一个应用环境中实现的程序可能无法用于另外一应用环境。

对于位操作符,由于系统不确保如何处理其操作数的符号位,所以强烈建议使用unsigned整型操作数。

左移操作符(<<)在右边插入0以补充空位。对于右移操作符(>>),如果其操作数是无符号位,则从左边开始插入0;如果操作数是有符号位,则插入符号位的副本或者0值,如何选择需依据具体的实现而定。移位操作的右操作数不可以是负数,而且必须是严格小于左操作数位数的值。否则,操作的效果未定义。

3.1 bitset对象或整型值的使用

3.2 将移位操作符用于IO

四、 赋值操作符

复制操作数的左操作数必须是非const的左值。

五、自增和自减操作符

六、sizeof操作符

sizeof操作符的作用是返回一个对象或类型名的长度,返回值的类型为size_t,长度的单位是字节。sizeof表达式的结果时编译时常量,该操作符有以下三种语法形式:

sizeof(type name);

sizeof ( expr);

sizeof expr;

将sizeof应用在表达式expr上,将获得该表达式的结果的类型长度。

将sizeof用于expr时,并没有计算表达式expr的值。特别是在sizeof *p中,指针p可以持有一个无效地址,因为不需要对p做解引用操作。

使用sizeof的结果部分地依赖所涉及的类型:

1、对char类型或值为char类型的的表达式做sizeof操作保证得1;

2、对引用类型做sizeof操作将返回存放此引用类型对象所需的内存空间的大小。

3、对指针做sizeof操作将返回存放指针所需的内存的大小;注意,如果要获取该指针所指向对象的大小,则必须对该指针进行解引用。

4、对数组做sizeof操作等效于将对其元素类型做sizeof操作的结果乘上数组元素的个数。

七、new和delete表达式

定义变量时,必须指定其数据类型和名字。而动态创建对象时,只需要指定其数据类型,而不必为该对象命名。取而代之的是,new表达式返回指向新创建对象的指针,我们通过该指针来访问此对象。

7.1 动态创建对象的初始化

动态创建对象可用初始化变量的方式实现初始化:

int i(1024);

int *pi = new int(1024);

string s(10, ‘9‘);

string *ps = new string(10. ‘9‘);

C++使用直接初始化语法规则初始化动态创建的对象。如果提供了初值,new表达式分配到所需要的内存后,用给定的初值初始化该内存空间。

7.2 动态创建对象的默认初始化

如果不提供显示初始化,动态创建的对象与函数内定义的变量初始化方式相同。对于类类型的对象,用该类的默认构造函数初始化;而内置类型的对象则无初始化。

7.3 耗尽内存

如果new表达式无法获取需要的内存空间,系统将抛出名为bad_alloc的异常。

7.4 撤销动态创建的对象

动态创建的对象用完后,程序员必须显示地将该对象占用的内存返回给自由存储区。C++提供了delete表达式释放指针所指向的地址空间。

7.5 零值指针的删除

如果指针的值为0.则在其上做delete操作是合法的,但这样没有任何意义:

int *ip = 0;

delete ip;

C++保证:删除0值的指针是安全的。

7.6 在delete之后,重设指针的值

删除指针后,该指针变成悬垂指针。悬垂指针指向曾经存放对象的内存,但该对象已经不再存在了。悬垂指针往往导致程序错误,而且很难检测出来。

一旦删除了指针所指向的对象,立即将指针置为0,这样就非常清楚地表明指针不再指向任何对象。

7.7 const对象的动态分配和回收

const int *pci = new const int(1024);

与其他常量一样,动态创建const对象必须在创建时初始化,并且一经初始化,其值就不能在修改。

警告:动态内存的管理容易出错

下面三种常见的程序错误都与动态内存分配相关:

(1)、删除(delete)指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏(memory leak)”。内存泄漏很难发现,一般需等应用程序运行了一段时间后,耗尽了所有的内存空间,内存泄漏才会显露出来。

(2)、读写已删除的对象。如果删除指针所指向的对象之后,将指针置为0值,则比较容易检测出这类错误。

(3)、对同一个内存空间使用两次delete表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做delete运算,将该对象的内存空间返还非自由存储区,然后接着delete第二个指针,此时则自由存储区可能会被破坏。

7.8  删除const对象

delete pci;

即使delete表达式的操作数是指向int型const对象的指针,该语句同样有效回收pci所指向的内容。

八、类型转换

表达式是否合法取决于操作数的类型,而且合法的表达式其含义也是由操作数类型决定。

如果这两个类型之间可以相互转换,则称这两个类型相关。

C++并不是把两个不同类型的值直接加在一起,而是提供了一组转换规则,以便在执行算术操作之前,将两个操作数转换为同一种数据类型。这些转换规则由编译器自动执行,无需程序员介入。因此,他们也被称为隐式类型转换。

8.1  何时发生隐式类型转换

编译器在必要时将类型转换规则应用到内置类型和类类型的对象上。在下列 情况下,将发生隐式类型转换:

1、在混合类型表达式中,其操作数被转换为相同的类型:

int ival;

double dval;

ival >= dval;//ival converted to double

2、用作条件的表达式被转换为bool类型:

3、用一表达式初始化某个变量,或将一表达式赋值给某个变量,则该表达式被转换为该变量的类型

8.2 算术转换

8.2.1 有符号与无符号类型之间的转换

若表达式中使用了无符号数值,所定义的转换规则需保护操作数的精度。unsigned 操作数的转换依赖于机器中整型的相对大小,因此,这类转换本质上依赖于机器。

8.3 其他隐式转换

8.3.1 指针转换

在使用数组时,大多数情况下数组都会自动转换为指向第一个元素的指针:

int ia[10];

int *ip = ia;

不将数组转换为指针的例外情况有:数组用作取地址(&)操作符的操作数或sizeof操作符的操作数时,或用数组对数组的引用进行初始化时,不会将数组转换为指针。

C++还提供了另外两种指针转换:指向任意数据类型的指针都可转换为void*类型;整型值常量0可转换为任意指针类型。

8.3.2 转换为bool类型

8.3.3 算术类型与bool类型的转换

8.3.4 转换与枚举类型

C++自动将枚举类型的对象或枚举成员转换为整型,其转换结果可用于任何要求使用整数值的地方。

九、显示转换

显示转换称为强制类型转换(cast),包括以下列名字命名的强制类型转换操作符:

static_cast、dynamic_cast、const_cast和reinterpret_cast。

9.1 何时需要强制类型转换

因为要覆盖通常的标准转换,所以需显示使用强制类型转换。

显示使用强制类型转换的另一个原因是:可能存在多种转换时,需要选择一种特定的类型转换。

9.2 命名的强制类型转换

时间: 2024-08-29 08:36:43

C++ Primer 第四版读书笔记(四)之表达式的相关文章

Java编程思想第四版读书笔记——第十三章 字符串

Java编程思想第四版读书笔记--第十三章 字符串 字符串的操作是计算机程序设计中最常见的行为. 关键词: StringBuilder ,StringBuffer,toString(),format转换,正则表达式, 1.不可变String String对象时不可变的.每当把String对象作为方法的参数时,都会复制一份引用.(其实就是对函数中参数列表中参数的操作不会影响外面的原参数) 如下: import static net.mindview.util.Print.*; public cla

C++ Primer 第四版读书笔记(八)之顺序容器

容器容纳特定类型对象的集合. 标准库vector类型,是一个顺序容器.它将单一类型元素聚集起来称为容器,然后根据位置来存储和访问这些元素,这就是顺序容器.顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定. 标准库定义了三种顺序容器类型:vector.list和deque.它们的差别在于访问元素的方式,以及添加或删除元素相关操作的运行代价.标准库还提供了三种容器适配器.实际上,适配器是根据原始的容器类型所提供的操作,通过定义新的操作接口,来适应基础的容器类型. 顺序容器类型 顺

C++ Primer 第四版读书笔记(六)之函数

内联函数.类成员函数和重载函数以及函数指针. 函数可以看作程序员定义的操作.与内置操作符相同的是,每个函数都会实现一系列的计算,然后(大多数时候)生成一个结算结果.但与操作符不同的是,函数有自己的函数名,而且操作数没有数量限制.与操作符一样,函数可以重载,这意味着同样的函数名可以对应对个不同的函数. 一.函数的定义 函数由函数名以及一组操作数类型唯一地表示.函数的操作数,也即形参(parameter),在一对圆括号中声明,形参与形参之间以逗号分隔.函数执行的计算在一个称为函数体(function

C++ Primer 第四版读书笔记(七)之标准IO库

C++的输入/输出由标准库提供.标准库定义了一组类型,支持对文件和控制窗口等设备的读写(IO).还定义了其他一些类型,使string对象能够像文件一样操作,从而使我们无需IO就能实现数据与字符之间的转换.一般来说,类的设计者还可以很方便地使用IO标准库设施读写自定义类的对象.类类型通常使用IO标准库为内置类型定义的操作符和规则来进行读写. 一.面向对象的标准库 迄今为止,我们已经使用IO类型和对象读写数据流,它们常用于与用户控制窗口的交互.当然,实际的程序不能仅限于对控制窗口的IO,通常还需要读

C++ Primer 第四版读书笔记(五)之语句

通常情况下,语句是顺序执行的.但是,除了最简单的程序外,只有顺序执行往往并不足够.为此,C++定义了一组控制流语句,允许有条件地执行或者重复地执行某部分功能. 1.1 简单语句 C++中,大多数语句以分号结束. 表达式语句用于计算表达式. 1.2 声明语句 在C++中,对象或类的定义或声明也是语句. 1.3 复合语句 复合语句,通常被称为块,使用一对花括号括起来的语句序列.块标识了一个作用域,在块中引入的名字只能在该块内部或者嵌套在块中的子块里访问.通常,一个名字只从其定义处到该块结尾这段范围内

C++ Primer 第四版读书笔记(三)之数组与指针

C++语言提供了两种类似于vector和迭代器类型的低级复合类型--数组与指针.与vector类型相似,数组也可以保存某种类型的一组对象:而它们的区别在于,数组的长度是固定的.数组一经创建,就不允许添加新的元素.指针则可以像迭代器一样用于遍历和检查数组中的元素. 现代C++程序应尽量使用vector和迭代器类型,而避免使用低级的数组和指针.设计良好的程序只有在强调速度时才在类实现的内部使用数组和指针. 数组是C++语言中类似于标准库vector类型的内置数据结构.与vector类似,数组也是一种

C++ Primer 第四版读书笔记(八)之顺序容器(续)

3.6 访问元素 如果容器非空,那么容器类型的front和back成员将返回容器内第一个或最后一个元素的引用. 访问顺序容器内元素的操作 c.back() 返回容器c的最后一个元素的引用.如果c为空,则该操作未定义 c.front() 返回容器c的第一个元素的引用.如果c为空,则该操作未定义 c[n] 返回下标为n的元素的引用 如果n<0或n>c.size(),则该操作未定义 只适用于vector和deque容器 c.at[n] 返回下标为n的元素的引用.如果下标越界,则该操作未定义 只适用于

C++ Primer 第四版读书笔记(一)之变量和基本类型

C++语言定义了几种基本类型:字符型.整形.浮点型等. 1.基本内置类型 C++定义了一组表示整数.浮点数.单个字符和布尔值的算术类型,另外还定义了一种称为void的特殊类型. 表1.1 C++:算术类型 类型 含义 最小存储空间 bool 布尔型 - char 字符型 8位 wchar_t 宽字符型 16位 short 短整型 16位 int 整形 16位 long 长整形 32位 float 单精度浮点型 6位有效数字 double 双精度浮点型 10位有效数字 long double 扩展

C++ Primer 第四版读书笔记(二)之标准库类型

C++定义了一个内容丰富的抽象数据类型标准库,其中最重要的标准库类型是string和vector,它们分别定义了大小可变的字符串和集合.string和vector往往将迭代器用作配套类型,用于访问string中的字符,或者vector中的元素. 另一种标准库类型为bitset,提供了一种抽象方法来操作位的集合. string类型支持长度可变的字符串,vector用于保存一组指定类型的对象. bitset类标准库类型提供了更方便和合理有效的语言级的抽象设施.通过这个类可以把某个值当作位的集合来处理