第四章:表达式
求值顺序
C++中没有明确规定大多数运算符的求值顺序,因此我们要避免:改变了某个运算对象的值,又在表达式其他地方使用这个运算对象。这种情况出现。
赋值运算满足右结合律。
在输出表达式中使用条件运算符:
条件运算符的优先级非常低,因此需要在两端加上括号。
在第二条表达式中,等价于。
类型转换
如果类型之间有关联,那么当程序需要一种类型的运算对象时,可以用另一种关联类型的对象或值来替代。如果两种类型可以相互转换,就是有关联的。
何时发生隐式类型转换
1.在多数表达式中,比int类型小的整数首先提升为较大的整数类型。
2.在条件中,非布尔值转换为布尔值。
3.在赋值语句中,右侧运算对象转换为左侧运算对象的类型。
4.如果算术运算或者关系运算的对象有多种类型,需要转换成同一种类型。
强制类型转换(cast)
强制转换的格式如下:
cast-name< type> (expression)
其中,type是转换的目标类型,expression是要转换的值。cast-name有如下几种类型。
static-cast
任何具有明确定义的类型转换,只要不包含底层const,都可以用static-cast。
const-cast
只能改变运算对象的底层const,用于将常量对象转换成费常量的对象。
第五章:语句
控制语句
switch语句的case标签必须是整型常量表达式。也就是说只可以用整数或者字符型常量。
第六章:函数
局部静态对象:
有些时候,有必要令局部变量的生命周期贯穿函数调用及之后的时间。因此可以将变量定义为static类型。局部静态对象在程序的执行路径第一次经过对象定义语句时候初始化,直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。
参数传递
和其他变量一样,形参的类型决定了形参和实参交互的方式。如果形参是引用类型,它将绑定到对应的实参上;否则,将实参的值拷贝后赋给形参。
当形参是引用类型时,我们说它对应的实参被引用传递,也就是说,引用形参是它对应的实参的别名。
当实参的值被拷贝给形参时,形参和实参是两个独立的对象。
return语句
引用返回左值
可以像使用其他左值那样来使用返回引用的函数的调用。特别的,我们能为返回类型非常量引用的函数的结果赋值。
不过,如果返回类型是常量引用,我们则不可以作为左值。
列表初始化返回值
C++11规定,函数可以返回花括号包围的值的列表。如果函数返回的是容器,列表中可以有多个值。如果返回的是内置类型,最多包含一个值。如果返回的是类类型,由类本身定义初始值如何使用。
返回数组指针
因为数组不能被拷贝,所以函数不能返回数组。不过可以返回数组的指针或引用。
为了返回函数指针,我们需要声明一个返回函数指针的函数。但是,我们可以使用类型别名来简化该操作,定义类型别名有以上两种方法。
arrT和arrT1是含有10个int整数的数组的别名。func函数接受一个int实参,返回一个指向含有10个整数的数组的指针。
返回函数指针的函数
和这些声明类似,我们想定义一个返回数组指针的函数,则必须含有数组的维度,我们可以用如下方法。
使用尾置数据类型
任何函数都可以使用尾置返回,但是这种形式对返回类型复杂的函数最有效。
尾置返回类型跟在形参列表后面并以->符号开头。为了表示函数真正的返回类型跟在形参列表之后,我们在本应该放返回类型的地方设置一个auto,如下:
assert宏
头文件是cassert,assert宏使用一个表达式作为它的条件:assert(expr);
首先对expr求值,如果为假(0),assert输出信息并终止程序运行,为真则什么也不做。
assert宏常用于检查不能发生的条件。
函数指针
函数指针指向的是函数而非对象,和其他指针一样,函数指针指向某种特定类型。
例如:
使用函数指针
如果定义了指向重载函数的指针,指针类型必须与重载函数中的某一个精确匹配。
函数指针形参
虽然不能定义函数类型的形参,但是形参可以是指向函数的指针。此时,形参是当成指针使用。
因此,我们可以直接把函数作为实参使用,此时会自动转换为指针。
useBigger(s1, s2, lengthCompare);
返回指向函数的指针
写法如下:
第七章:类
this常量指针
成员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象。当我们调用一个成员函数时,用请求该函数的对象地址初始化this。
例如,我们调用total.isbn() ,则编译器将total的地址传递给isbn的隐式形参this,等价于Sales_data::isbn(&total)
定义一个返回this对象的函数
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
//将rhs的成员加到this对象的成员上
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this; //返回调用该函数的对象
}
其中,return语句解引用this指针以获得执行该函数的对象。
类的静态成员
有时候类的一些成员与类本身相关,而不是与类的各个对象保持关联。
例如,银行账户类需要一个成员来表示当前的利率,我们希望利率与这个类关联,不是与每个银行账户对象关联,没有必要每个对象都存储利率。更重要的是,如果利率变化,我们希望所有的对象都能使用新值。
声明静态成员
在成员的声明前加上关键字static。静态成员可以是public或者private,类型可以是常量、引用、指针、类等。
使用静态成员
我们使用作用域运算符直接访问静态成员。
或者我们可以使用类的对象、引用、指针来访问静态成员
定义静态成员
我们既可以在类的内部也可以在外部定义静态成员函数。在类的外部定义时,不能重复static关键字,该关键字只出现在类内部的声明语句。
第八章:IO库
istream:输入流类型,提供输入操作
ostream:输出流类型,提供输出操作
cin:一个istream对象,从标准输入读出数据
cout:一个ostream对象,向标准输出写入数据
ceer:一个ostream对象,用于输出程序错误消息,写入到标准错误
*>>:用于从一个istream对象中读取输入数据
<<:用来像一个ostream对象写入输出数据
getline:用于从一个给定的istream读取一行数据,存入一个给定的string对象中
刷新输出缓冲区:
endl:换行并刷新缓冲区
flush:刷新缓冲区
文件输入输出
文件模式:
in:以只读方式打开
out:以写方式打开
app:每次写操作前均定位到文件末尾
ate:打开文件后立即定位到文件末尾
trunc:截断文件
以out模式打开文件会丢弃已有数据
默认情况下,当我们打开一个ofstream时,文件内容会被丢弃。阻止一个ofstream清空给定文件内容的方法是同时指定app模式。
ofstream app("file",ofstream::out | ofstream::app);
string流
sstream头文件定义了三个类型来支持内存IO,可以从string读取数据,向string写入数据。
istringstream、ostringstream、stringstream分别是读数据、写数据、既可以读又可以写。
使用istringstream
例如:假设有一个文件,列出了一些人和他们的电话号码。某些人只有一个号码,某些人则有多个号码。我们的输入文件可能是如下的:
morgan 2015151555 674845854854
drew 05855555
lee 4124115677 5345378888 9534534534
文件中每条记录都以一个人名开始,后面跟随一个或多个电话号码。
我们先用getline从标准输入读取整条记录,如果调用成功,那么line中将存着从输入文件而来的一条记录。
在while中,我们定义了一个局部PersonInfo存放当前记录的数据。
接下来我们将一个istringstream与刚刚读取的文本行绑定,这样就可以在此istringstream上使用输入运算符来读取当前记录的每个元素。