敏捷开发学习笔记(思维导图)
Filed Under (新长征路上的代码) by 逆铭 on 2009-07-04 18:06
终于看完了《Agile Principles, Patterns, and Practices in C#》的第一个Section,上学期间读这些书的进度还真不是一般的慢……第一次尝试用MindMap做笔记,感觉不错,不过效率还是不够高。老蒋说我笔记做得太详尽了,像抄书…反思中。
篇幅所限,书中还是有很多内容不够深入。一些内容需要另一本书的篇幅深入讨论(如重构),甚至需要看一本书才能从纸上谈兵转到实践(如TDD、Acceptance Tests)。。。望不到头的书单啊T_T
做笔记使用的工具是 XMind。
单击这里进入下载页面。
(需要下载才能看到全部内容)
Tags:csharp, 思维导图, 敏捷开发, 读书笔记
C++ Primer 读书笔记 – 第八章
Filed Under (新长征路上的代码) by 逆铭 on 2008-09-02 15:12
第8章 标准IO库
⒈ IO标准库类型
类名 派生自 头文件 描述
istream ios iostream 输入流
ostream ios iostream 输出流
iostream istream和ostream iostream 输入/输出流
ifstream istream fstream 输入文件流
ofstream ostream fstream 输出文件流
fstream iostream fstream 输入/输出文件流
istringstream istream sstream 输入字符串流
ostringstream ostream sstream 输出字符串流
stringstream iostream sstream 输入/输出字符串流
⑴ 标准库分别实现了以上继承层次的的两个版本,分别面向 char 类型(如上)和 wchar_t 类型
后者采用和前者一样的命名规则,仅在每个类和对象名前加上字母w以示区别
⑵ IO对象不可赋值或赋值
⒉ 标准输入输出对象
extern istream cin; 标准输入流
extern ostream cout; 标准输出流
extern ostream cerr; 标准错误输出流
extern ostream clog; 标准日志输出流
⒊ 文件输入输出流
⑴ 使用 ifstream, ofstream 和 fstream 型对象可以实现对文件的读写
⑵ 可以调用公共成员函数 open 或在创建时使用构造函数使流对象关联到一个文件
二者都接受两个参数:一个C风格字符串表示文件名,一个可选的 ios_base::openmode 型值表示流打开模式
① openmode 是用以表示流打开模式标识的位掩码类型,支持位操作符
该类型对象的值可以是以下打开模式标识或它们之间进行位操作所得的结果
和以下(openmode 型)模式标志均为 ios_base 的公共成员
Ⅰ app (append)每次执行输出操作前都定位到流的末尾
Ⅱ ate (at end)打开时定位到流末尾
Ⅲ binary 在二进制(而非文本)模式下操作
Ⅳ in (input)允许输入操作
Ⅴ out (output)允许输出操作
Ⅵ trunc (truncate)抛弃流中现存的所有内容,打开时假定长度为0
(openmode 和上述标识分别是 ios_base 的公共成员类型和公共成员常量)
② fstream 默认使用 in | out 模式
ifstream 自动使用 in 模式
ofstream 自动使用 out 模式(效果上等同于 out | trunc)
⑶ 完成文件操作后可以使用公共成员函数 void close() 关闭
关闭后可以再次 open 新文件,但之前应调用 clear 清除该流的状态
流对象被析构时也会自动调用 close()
⒋ 字符串流
⑴ 常用于特定数据类型和格式化的字符串之间的相互转换
⑵ 3个类的构造函数各有带或不带 string 形参的两个不同版本
使用带 string 参数的版本,则创建储存该实参副本的字符串流对象
⑶ 3个类的都有公共成员函数 str,它的两个版本分别返回和设置与该流对象相关的 string 对象
string str() const;
返回与该流对象相关的 string 对象
string str(const string&);
将该流对象相关的 string 对象设置为实参的副本
⒌ 条件状态
⑴ 流对象内都用一个 iostate 型值表示条件状态
· iostate 是用以表示流错误状态标志的位掩码类型,支持位操作符
该类型对象的值可以是以下条件状态标识或它们之间进行位操作所得的结果
Ⅰ eofbit 输入操作中遇到文件结束符(同时会设置failbit)
Ⅱ failbit 输入操作失败(通常可恢复)
Ⅲ badbit 流被损坏(通常不可恢复)
Ⅳ goodbit 没有错误,值为0
(iostate 和上述标识分别是 ios_base 的公共成员类型和公共成员常量)
⑵ 查询条件状态
bool ios::eof() const;
eofbit位被设置则返回 true, 否则返回 false
bool ios::fail() const;
failbit 或 badbit 位被设置则返回 true, 否则返回 false
bool ios::bad() const;
badbit 位被设置则返回 true, 否则返回 false
bool ios::good() const;
流对象有效则返回 true, 否则返回 false
ios_base::iostate rdstate() const;
返回当前条件状态
⑶ 控制条件状态
void ios::clear( ios_base::iostate = goodbit);
使用参数值替换当前条件状态
void ios::setstate( ios_base::iostate );
将参数状态加入当前状态(如同使用了位或操作符|)
⑷ 可以直接检查流对象的真值来确认是否可用
⒍ 输出缓冲区的管理
每个IO对象都管理一个缓冲区,作为流和写入目标间的媒介
下面几种情况将导致输出流被刷新(即写入到真实的输出设备或者文件)
⑴ 程序正常结束或目标文件被关闭
注: 程序崩溃不会刷新缓冲区
调试崩溃的程序时如果用最后的输出定义错误位置,应确保缓冲区已刷新
因此输出时应多使用endl而非‘\n’
⑵ 当缓冲区满时会自动刷新
⑶ 使用操纵符显式刷新缓冲区
(以下均定义在<ostream>中)
① endl 输出换行符并刷新缓冲区
② flush 刷新缓冲区(不添加任何字符)
③ ends 输出空字符‘\0′并刷新缓冲区
注:cplusplus.com,cppreference.com和msdn上都没有表示ends会刷新缓冲区,存疑
⑷ 使用 unitbuf 操纵符可以设置流对象的相关格式状态标志,使缓冲区在每次插入操作后都刷新
使用 nounitbuf 操纵符可以恢复为正常的、系统控制的缓冲区刷新方式
⑸ 可以把流对象绑定到一个输出流对象,前者进行任何I/O操作都会刷新后者
① 可以使用 ios::tie 公共成员函数查询、修改绑定状态
ostream* ios::tie() const;
返回指向所绑定到的输出流对象的指针
ostream* ios::tie( ostream* );
绑定到参数中指针指向的输出流对象(实参为0则解除绑定),并返回指向原绑定对象的指针
② cin, cerr, clog 默认绑定到 cout, 而它们的宽字符版本则默认绑定到 wcout
⒎ 控制格式状态
istream/ostream(及它们的派生类)对象都支持使用提取操作符(>>)/插入操作符(<<),从流中提取/向流中插入格式化的对象数据
把提取/插入操作符和一些操纵符(manipulator)一起使用,可以改变流对象的特性或格式设置
其中除setbase,setprecision,setw,setfill定义在头文件<iomanip>中外,其余操纵符均定义在<ios>中
⑴ 布尔值格式
从流中提取/向流中插入布尔值时形式使用 0, 1(默认) 还是 false, true
· 使用操纵符 boolalpha noboolalpha
⑵ 整数格式
① 基数设置
从流中提取/向流中插入整数时使用八进制、十进制(默认)还是十六进制
· 使用操纵符 oct dec hex
· 使用操纵符 setbase(int) (实参只能是8,10或16)
② 基数前缀设置
向流中插入整数时是否显示基数前缀(八进制的0和十六进制的0x)(默认不显示)
· 使用操纵符 showbase noshowbase
③ 十六进制和科学计数法中字母的大小写设置
向流中插入整数时若使用十六进制或科学计数法,出现的字母使用小写(默认)还是大写
· 使用操纵符 uppercase nouppercase
⑶ 浮点数格式
① 精度设置
向流中插入浮点数精度为多少(默认为6)
· 使用 ios_base 的公共成员函数 precision 可以获得和设置流的浮点数精度
streamsize precision() const;
返回流对象的浮点数精度
streamsize precision( streamsize );
设置流的浮点数精度为实参值并返回先前的精度值
· 使用操纵符 setprecision( streamsize )
以上 streamsize 为表示流中大小的实现类型,是一个带符号基本整型的别名
注: 精度的解释在使用不同情况下不同
· 默认情况下解释为最大有效数字(位数不足不用小数末尾的零补齐)
· 在强制使用fixed,scientific或showpoint时解释为小数点后的确切位数(位数不足则用小数末尾的零补齐)
② 计数法设置
向流中插入浮点数时,让系统自动选择计数法(默认),还是强制指定为定点计数法或科学计数法
· 使用操纵符 fixed scientific
· 计数法不存在恢复默认的操纵符,但可以通过给成员函数 unsetf 传入常量 floatfield 达到目的
(unsetf 和 floatfield 均为 ios_base 的公共成员)
③ 小数点显示设置
向流中插入浮点数时,若小数部分为0,是否显示小数点和小数部分的0(默认不显示)
· 使用操纵符 showpoint noshowpoint
④ 非负数(整数和浮点数)正号设置
向流中插入非负数(包括0)时是否显示正号+ (默认不显示)
· 使用操纵符 showpos noshowpos
⑷ 对齐和填充格式
① 使用操纵符 setw( streamsize ) 可指定下次对流的插入操作的最小字段长度
注: 和endl一样,它不改变流的内部状态,只影响下一个输出
② 使用操纵符 setfill( char ) 设置向流中插入对象时用来填充字段的字符(默认为空格)
③ 字段内对齐方式设置(默认左对齐)
· 使用操纵符left right internal
关于internal:
- 对数值表示左对齐前缀(正负号和十六进制的0x)右对齐数值
- 对非数值则与 right 等效
⑸ 空白字符的处理
· 使用操纵符 skipws noskipws 设置从流中提取对象时是否忽略空白字符(默认忽略)
· 使用操纵符 ws 忽略输入序列中从当前位置开始尽可能多的空白字符,直到遇到非空白字符才停止
当然,如果已经(默认)设置了 skipws 则没有必要使用 ws
⒏ 无格式I/O操作
⑴ 单字节操作
① istream& get ( char& );
istream 的公共成员函数,从流中提取一个字符存入实参中
int get( );
无参数版本从流中提取一个字符并返回其值
② ostream& put ( char );
ostream 的公共成员函数,将字符参数值写入输出缓冲区并返回*this
③ istream& putback ( char );
istream 的公共成员函数,将字符参数值放回流中并返回*this
④ istream& unget ( );
istream 的公共成员函数,将流退回1字节并返回*this
⑤ int peek ( );
istream 的公共成员函数,读取并返回流中的下一个字符,但不提取它
注: 为允许返回EOF,put(无参数版本)和peek的返回值都为 int
⑵ 多字节操作
① istream& get (char* s, streamsize n, char delim );
istream 的公共成员函数,不断从流中提取字符并以字符串形式存入s指向首地址的数组,
直到出现以下情况之一:
- 已经提取了(n-1)个字符;
- 遇到了定界字符delim(如果不提供此参数则为‘\n’);
(被找到的定界字符不会被提取,而是继续留在流中作为下一个要被提取的字符)
- 到达文件末尾;
- 提取过程中发生错误;
最后返回*this.
注: 提取的字符以字符串的形式储存,故将自动添加结尾的‘\0′,而被提取的最大字符数也为(n-1)而非n
② istream& getline (char* s, streamsize n, char delim );
istream 的公共成员函数,与上面参数表相同的get版本类似,唯一区别在于定界字符会被提取并丢弃
③ istream& read ( char* s, streamsize n );
istream 的公共成员函数,从流中提取n个字符存入s指向首地址的数组,
直到出现以下情况之一:
- 已经提取了n个字符
- 到达文件末尾(eofbit和failbit会被设置)
- 提取过程中发生错误
最后返回*this.
注: 与get和getline不同,read不把提取的字符保存为字符串,故不会自动加上‘\0′
④ streamsize gcount ( ) const;
istream 的公共成员函数,返回上次无格式输入操作提取的字符个数
(peek, putback, unget不提取字符,故对此gcount返回0)
⑤ ostream& write ( const char* s , streamsize n );
ostream 的公共成员函数,把s指向首地址的数组的前n个字符写入输出流缓冲区
⑥ istream& ignore ( streamsize n = 1, int delim = EOF );
istream 的公共成员函数,从流中提取并抛弃字符,直到:
- 已经提取了n个字符或遇到了定界字符delim(该字符不会被提取)
最后返回*this.
⒐ 流的随机访问
⑴ 用于随机访问的成员函数
· pos_type tellg ();
pos_type tellp ();
返回输入/输出流中的标记当前的绝对位置
· istream& seekg ( pos_type pos );
ostream& seekp ( pos_type pos );
将输入/输出流中的标记重新定位至参数值表示的位置
· istream& seekg ( off_type off, ios_base::seekdir dir );
ostream& seekp ( off_type off, ios_base::seekdir dir );
将输入/输出流中的标记重新定位至距离dir偏移量为off的位置
⑵ 关于上述函数参数和返回值的类型
① pos_type和off_type都是类的成员类型,分别表示流中的标记位置和偏移量
后者可正可负,分别表示向前和向后偏移
② seekdir类型用来表示偏移的启示位置,其可能值如下
beg 流的开头
cur 流的当前位置
end 流的末尾
⑶ 以上tell和seek版本分别有两个版本g(get)和p(put)
其区别在于g版是istream类的成员,而p版是ostream类的成员
对于iostream对象,而者都适用,它们都操作同一个标记(而非输入输出各一个)
⑷ 普通iostream对象一般不允许随机访问,以上内容主要适用fstream和sstream
Tags:cpp, 读书笔记
C++ Primer 读书笔记 – 第七章
Filed Under (新长征路上的代码) by 逆铭 on 2008-08-28 17:14
第7章 函数
㈠ 函数的声明和定义
⒈ 与变量类似:
⑴ 函数必须在调用前声明
⑵ 函数声明可与定义分离
⑶ 一个函数只能定义一次但可声明多次
⒉ 函数声明由函数返回类型、函数返回类型和形参列表组成
三者描述了函数的接口,称为函数原型(function prototype)
⑴ 函数的操作数,即形参(parameter),在一对圆括号中声明,并以逗号分隔
形参名是可选的,但形参需要在定义函数时命名才能使用
⑵ 函数执行的运算在一个称为函数体(function body)的块语句中定义
⒊ 函数一般在头文件中声明,在源文件中定义
此时应使后者包含前者,以便编译器检查定义和声明是否一致
⒋ 将一个较小的、常被调用的函数指定为 inline 可使函数在调用点展开,以避免调用函数的额外开销
但内联说明对编译器来说只是一个建议,编译器也可能选择忽略
㈡ 函数的调用和参数传递
⒈ 函数的调用
⑴ 使用调用操作符()实现函数调用
① 操作数是函数名和一组(可能为空的)用逗号分开的实参(argument)
② 结果类型为函数返回值的类型,结果为函数的返回值
⑵ 函数调用做两件事:
① 首先(隐式)定义形参,并用对应的实参进行初始化
· 形参的初始化与变量一样:
如果形参为非引用类型则复制实参的值,如果形参为引用类型则它只是实参的别名
② 主调函数(calling function)的执行被挂起,被调函数(called function)开始执行
⒉ 非引用形参
⑴ 指针形参
① 可以通过传入指针来间接访问指针所指对象
② 若需要保护指针指向的对象,可指定形参为指向 const 对象的指针
⑵ const 形参
① 用来初始化 const 形参的实参无论是不是 const 都可以
在函数中不能改变该实参的局部副本
② 非引用形参是否为 const 不影响编译器对其所属函数类型的判别
·注:对于指针,注意区分 const 是修饰指针本身的性质还是所指对象的性质
⑶ 不适合复制实参的情况
① 需要修改实参值时
② 需要将大型对象作为实参传递时
③ 无法复制对象时
以上情况可通过将形参定义为指针或引用类型解决
⒊ 引用形参
⑴ 可以使用引用形参返回额外信息
⑵ 可以利用 const 引用形参避免复制实参
⑶ 使用引用形参时,将不需要修改的定义为 const 会更灵活
非 const 引用形参不能用 const 左值或右值初始化,而定义为 const 则无此问题
⒋ 一般通过传递迭代器来传递 vector 等容器
⒌ 数组形参
⑴ 当把数组直接作为实参传给函数时:
① 若形参不是数组的引用,则自动转换为指向首元素的指针
例如以下三种定义完全等价:
void f(int*); //推荐,明确指出操作对象为指针
void f(int[]);
void f(int[10]);//维数被编译器忽略,写法容易引起误解
② 若形参是数组的引用则不发生转换,函数得到的是数组本身
此时编译器会检查形参和实参数组的维数是否匹配
⑵ 把数组传递给函数处理时,可以:
⒈ 使用标准库规范,即传入首元素指针和超出末端指针
⒉ 传递数组首元素地址,并显式传递表示数组大小的形参
⑶ 可以通过传递指向数组的指针来传递多维数组
⒍ 含有可变形参的函数
为兼容C语言而保留的特性,只能传入简单数据类型,大多数类类型对象都不能正确复制
⒎ 默认实参
⑴ 通过给形参表中的形参提供明确的初值可指定默认实参,如
void f( int, int = 1, int = 2 );
① 默认实参可以是任何适当类型的表达式
② 如果一个形参有默认实参,则其后的所有形参都必须有默认实参
③ 在一个文件中,只能为一个形参指定默认实参一次
通常应在函数声明中指定默认实参,并将该声明放在合适的头文件中
⑵ 调用函数时可省略有默认值的实参:若省略则使用默认实参,否则使用用户提供的实参
· 默认实参只能用来替换函数调用缺少的靠后的实参
因此设计带有默认实参的函数时,应将最少使用默认实参的形参排在最前,最多使用默认实参的形参排在最后
㈢ 局部对象的作用域和生命期
⒈ 函数体是一个作用域,在其中定义的变量称为局部变量(local variable),只可在该函数中访问
局部变量和形参均不能重名
⒉ 自动对象(automatic objects)是局部于函数的对象,会在每次函数调用时重新创建,并在函数结束时撤销
非静态局部变量和形参都是自动对象
⒊ static 局部对象确保不迟于在程序执行流程第一次经过该对象的定义语句时初始化,一旦创建在程序结束前都不会撤销
在所在函数被多次调用的过程中,static 局部对象会持续存在并保持它的值
㈣ 函数的返回值和 return 语句
⒈ 函数返回类型可为内置类型、类类型或复合类型,但不能是另一个函数或内置数组类型
为 void 类型表示该函数不返回任何值
⒉ return 语句
用于结束当前函数,将控制权返回给该函数的主调函数
⑴ 没有返回值的 return 语句
① 只能用于返回类型为 void 的函数
② 非必需,隐式 return 发生在函数最后一个语句完成时
⑵ 具有返回值的 return 语句
① 返回类型不是 void 的函数必须返回一个值(主函数 main 除外)
注:应在函数中的每条执行路径末尾都提供 return 语句;若不提供编译器可能也无法发现
② 用函数返回值初始化在调用函数处创建的临时对象,与用实参初始化形参的方法一样
即若返回非引用类型则得到副本,若返回引用类型则得到对象本身
③ 切勿返回局部对象的引用或指针
㈤ 函数的重载
⒈ 出现在相同作用域中的两个函数,如果具有相同的名字而形参表不同,则为重载函数(overloaded function)
仅仅是返回类型不同、默认实参不同、非引用形参的 const 性质不同不能实现重载
⒉ 若局部地声明函数,则该函数屏蔽而非重载在外层作用域中声明的同名函数
⒊ 重载确定的三个步骤
⑴ 确定候选函数集合
候选函数(candidate function)是与被调函数同名的函数,且在调用点上声明可见
⑵ 从候选函数集合中选择可行函数(找不到则此调用错误)
可行函数(viable function)满足两个条件:
① 函数形参与该调用的实参个数匹配(考虑默认实参)
② 每个实参的类型须与对应形参匹配(类型相同或可隐式转换)
⑶ 寻找最佳匹配(有多个匹配程度相同的则调用有二义性)
原则是实参类型与形参类型越接近则匹配越佳。具体匹配程度从高到低为:
① 精确匹配:实参与形参类型相同
② 通过类型提升实现的匹配
③ 通过标准转换实现的匹配
④ 通过类类型转换实现的匹配
㈥ 函数指针
⒈ 定义形式
返回类型 (*标识符)(形参表)
⒉ 可使用 typedef 简化定义
typedef 返回类型 (*自定义类型名)(形参表)
⒊ 对函数指针进行初始化和赋值,可使用:
⑴ 同类型的函数
引用函数名但不调用该函数时,函数名被自动解释为指向函数的指针
因此可以直接使用函数名对函数指针初始化或赋值,不需要使用取地址操作符&
·注:指针类型须与函数完全匹配
⑵ 同类型的函数指针
⑶ 0值常量表达式
⒋ 通过函数指针调用函数
可以不使用解引用操作符,直接使用函数调用操作符()调用所指函数
⒌ 函数指针作形参时,星号*可写可不写
⒍ 函数的指针作函数返回值
函数指针返回类型 (*函数名(函数形参表))(函数指针形参表)
㈦ 主函数 main
⒈ 返回值
⑴ 主函数返回类型为 int, 返回值在大多数系统中是一个状态指示器
返回0表示程序运行成功,其它大部分值表示失败
⑵ 不需要显式使用 return 语句,编译器将隐式插入返回0的语句
⑶ 为使返回值独立于机器,cstdlib 头文件定义了两个预处理变量
EXIT_FAILURE(运行失败) EXIT_SUCCESS(运行成功)
⒉ 使用主函数形参处理命令行选项
int main(int argc, char* argv[])
· argv为一个C风格字符串数组,储存了从命令行调用程序时输入的字符串(包括程序名和参数)
· argc表示argv中字符串的个数
⒊ 主函数 main 不允许被显式调用、取地址或重载
Tags:cpp, 读书笔记
C++ Primer 读书笔记 – 第六章
Filed Under (新长征路上的代码) by 逆铭 on 2008-08-24 17:01
第6章 语句
㈠ 简单语句
⒈ 表达式语句(expression_r statement)
一个表达式加上结尾的分号,执行时导致该表达式被求值
⒉ 空语句(null statement)
只由一个单独的分号组成,当语法上需要一个语句但逻辑上并不需要时使用
⒊ 声明语句
用于声明或定义对象或类
㈡ 复合语句
⒈ 复合语句(compound statement)又被称为块(block),是用一对花括号{}括起的(可能为空的)语句序列
⒉ 通常用于语法规则要求使用单个语句但程序逻辑需要多个语句时
⒊ 块标示了一个作用域,在块中引入的名字只能在其内部访问
㈢ 控制流语句
注:作为语句控制结构的一部分定义的变量,仅在该语句内可见
⒈ 条件分支结构
⑴ if 语句
关于 else-if 匹配的二义性问题: else 匹配给最后出现尚未匹配的 if
⑵ switch 语句
① switch 在计算表达式的值后跳转到匹配的标号处(无匹配则跳转至 default),并从该点开始一直执行下去,
直至 switch 语句结束或遇到 break 语句
② switch 求解表达式的结果须为整型,每个 case 标号的值也须为各不相同的整型常量表达式
③ switch 内部的变量定义
· 可以在 switch 求解的表达式中定义和初始化变量
· 为防止跳过变量定义,只允许在最后一个标号后定义变量
· 也可以引入块语句,在其中定义变量
⒉ 循环
⑴ while 语句
注:循环条件中定义的变量在每次循环时都要经历创建和撤销的过程
⑵ for 循环语句
注:语句头中的初始化语句、循环条件和表达式三者都可以省略
循环条件省略表示永远为 true
⑶ do while 语句
注:不能在循环条件中定义变量
⒊ break 语句
用于结束最近的外围 while, do while, for 或 switch 语句,并在该语句后继续执行
⒋ continue 语句
导致最近的外围循环语句(for, while, do while)正在进行的这次迭代提前结束
⒌ goto 语句
⑴ goto 语句提供了函数内部的无条件跳转,实现从 goto 语句跳转到同一函数内某个带标号的语句
除非有足够理由,应避免使用 goto 语句
⑵ 在任何语句前提供一个标识符和冒号,就得到一个带标号的语句(labeled statement)
标识符: 语句
使用 goto 语句跳转到该语句: goto 标识符;
由于这里的标识符只能用作 goto 的目标,因此可以与其它类型的标识符(如变量名)同名
⑶ goto 语句不能跨越变量的定义语句向前跳转
若确实需在 goto 和跳转目标位置间定义变量,则须定义在块中
⒍ try, catch 语句和 throw 表达式
用于异常处理
⒎ return 语句
用于结束当前函数,返回函数被调用处继续执行
⒍⒕ 使用预处理器进行调试
⒈ 使用 NDEBUG 预处理变量实现有条件的调试代码(类似头文件保护符)
#ifndef NDEBUG
#define NDEBUG
// 调试代码
#endif
如果定义了 NDEBUG 就不执行调试代码
⒉ 使用 NDEBUG 预处理变量以及 assert 预处理宏
定义在头文件cassert中,常用来检查不可能发生的状况,形式为
assert(表达式)
如果表达式结果为 false, assert 输出信息并终止程序
如果定义了 NDEBUG 预处理变量,assert 将被忽略,不会产生任何运行时代价
⒊ 预处理器定义了四种在调试时有用的常量
__FILE__ 文件名
__LINE__ 当前行号
__TIME__ 编译时间
__DATE__ 编译日期
Tags:cpp, 读书笔记
C++ Primer 读书笔记 – 第五章
Filed Under (新长征路上的代码) by 逆铭 on 2008-08-23 01:31
第5章 表达式
⒈ 表达式(expression_r)是一个C++程序中最低级的计算,由一或多个用一个操作符(operator)连接起来的操作数(operands)组成
⒉ 每个表达式都产生一个结果。表达式可以用作操作数,因此可用多个操作符编写复合表达式
⒊ 在求解表达式的过程中如果需要储存运算结果,编译器会自动创建没有名字的临时对象(temporary object),这些对象会在外围最大的表达式结束后释放
⒋ 表达式是否合法、合法表达式含义如何(执行什么操作、结果是什么类型)均取决于操作数的类型
⒌⒈ 算术操作符
⒈ 按优先级从高到低排列为:
一元正+, 一元负-; 乘法*, 除法/, 取模%; 加法+, 减法-
⒉ 关于除法/
⑴ 两整数相除结果仍为整数,商的小数部分被截去
⑵ 一正一负两整数相除,结果值向0一侧还是向-∞一侧取整依赖于机器
⒊ 关于取模
⑴ 操作数只能为整型
⑵ 两操作数均为负时结果为负或0;
两操作数一正一负时,结果的符号随哪个操作数而定依赖于机器
⒌⒉ 关系操作符和逻辑操作符
⒈ 按优先级从高到低排列为:
逻辑非!; 小于<, 小于等于<=, 大于>, 大于等于>=; 相等==, 不等!=; 逻辑与&&; 逻辑或||
⒉ 关系操作符和逻辑操作符接受算术或指针型操作数,并返回 bool 型值
逻辑操作符视其操作数为条件表达式
⒊ 逻辑与&&和逻辑或||操作符支持短路求值(short-circuit evaluation)
⒋ 不应串接使用关系操作符
形如i<j<k的表达式得不到预期结果
⒌⒊ 位操作符
⒈ 按优先级从高到低排列为:
位取反~; 左移<<, 右移>>; 位与&; 位异或^; 位或|
⒉ 位操作符使用整型操作数,将其视为二进制位的集合
由于负整数的符号位如何处理依赖于机器,因此应使用 unsigned 整型操作数
⒌⒋ 赋值操作符
⒈ 赋值操作符的左操作数须为非 const 左值
赋值表达式的结果即为其左操作数(左值)
⒉ 赋值操作符从右向左结合,因此当各操作数都有相同的通用类型时,允许在一个表达式中进行多次赋值,如:
i = j = k = 0;
⒊ 复合赋值操作符
对于任意二元算术操作符或二元位操作符 op
a op= b;
相当于
a = a op b;
二者显著的差别在于前者只计算了一次左操作数,后者则计算了两次
⒌⒌ 自增和自减操作符
⒈ 自增++和自减–操作符为对象加1或减1提供了方便简短的实现方式,有前置和后置两种使用形式
前置操作返回加(减)1后的对象(左值),后置操作返回操作数的原值(右值)
⒉ 出于性能考虑,应只在必要时才使用后置操作符
后置操作符需要先保存原值以便返回,而前置操作符只需加(减)1后直接返回对象即可
⒌⒍ 箭头操作符
箭头操作符用于获取指针指向类类型对象的成员。
下面两个表达式等价:
p->foo;
(*p).foo;
⒌⒎ 条件操作符
⒈ 条件操作符是C++中唯一的三元操作符,能将简短的 if-else 语句嵌入表达式
格式为 cond ? expr1 : expr2
首先计算 cond 值,若为 true 则计算并返回 expr1, 为 false 则计算并返回 expr2
⒉ 避免深度嵌套以保证可读性
⒌⒏ sizeof 操作符
⒈ sizeof 操作符用于返回一个对象或类型的大小(单位字节,类型 size_t)
形式为 sizeof expr
或 sizeof(type_name)
⒉ sizeof 表达式的结果是编译时常量
对表达式使用 sizeof 时该表达式的值并不会被计算
⒊ 对数组作 sizeof 将得到整个数组在内存中的长度
⒌⒐ 逗号操作符
逗号表达式是一组由逗号分隔的表达式,从左向右计算并返回最右边表达式的值(若该表达式为左值则返回左值)
⒌⒒ new 和 delete 表达式
⒈ new 和 delete 表达式分别用于动态创建和释放单个对象或一个数组
⒉ new 表达式
⑴ new 表达式动态创建单个对象或一个数组,并返回指向该对象或数组首元素的指针
① 动态数组维数为0值时也将返回有效的非零指针,但不能解引用
② 可以创建动态的 const 对象或数组,它们无法修改但可以释放
③ 如果无法获取需要的空间,系统将抛出 bad_alloc 异常
⑵ 分配与对象(或数组元素)初始化
① 默认内置类型不初始化,类类型调用默认构造函数(必须提供)
单个对象: new [const] 类型名
一个数组: new [const] 类型名[维数]
② 添加空括号()可执行值初始化(value initialization)
即内置类型对象置为0,类类型对象调用默认构造函数(必须提供)
单个对象: new [const] 类型名()
一个数组: new [const] 类型名[维数]()
注:对于后者,我使用的编译器中,VC初始化后会把元素置为0,但mingw不会
③ 执行直接初始化
单个对象: new [const] 类型名(初始化式)
动态数组元素不支持类似初始化方式
⒊ delete 表达式
⑴ 由 new 动态分配的对象或数组需要显式地使用 delete 表达式释放(否则会造成内存泄漏)
⑵ delete ptr 和 delete[] ptr 分别释放单个对象和动态数组
① 如果指针不指向由 new 分配的对象,则对其 delete 不合法
例外:对零指针 delete 是合法的
② 读写已释放的对象或对同一内存空间多次 delete 都可能导致错误
因此 delete 之后应立即重置该指针的值(一般重置为0)
③ 释放动态数组如果丢掉方括号[],将可能导致编译器无法发现的错误
⒌⒑ 复合表达式的求值
⒈ 含有两个或以上操作符的表达式称为复合表达式(compound expression_r)
操作数和操作符的结合方式决定了符合表达式的值,而前者取决于操作符的优先级和结合性:
操作数优先与优先级更高的操作符结合;操作符优先级相同时则由结合性决定结合方向
⒉ 圆括号()凌驾于优先级之上
若不确定结合方式,则使用圆括号()强制确定操作数的组合
⒊ 结合方式确定并不意味着操作数的计算顺序并不确定
若修改了操作数的值,则不要在同一语句的其它地方再使用它,除非操作数的计算次序不成问题
⒋ 运算符优先级与结合性表
⒌⒓ 类型转换
⒈ 隐式类型转换
两个类型间存在可转换关系,则称两个类型相关
⑴ 何时发生
当编译器期望获得某种类型的数据却得到另一种类型的,就会尝试自动转换类型
具体情况包括:
① 表达式中不同类型的多个操作数被转换到同一类型
② 用作条件的表达式被转换为 bool 型
③ 用一表达式对某变量初始化或赋值时,前者转换为后者的类型
④ 给函数传递实参和返回值时可能发生隐式类型转换
⑵ 内置类型转换规则
① 算术类型间的转换
ⅰ 浮点型转换为整型时小数部分被抛弃(在赋值、初始化等情况下发生)
ⅱ 二元(算术、关系等)操作符表达式中,为试图保留精度会把较小的类型转换为较大的类型
a类型提升
· 将比 int 小的整型提升为 int 或(当 int 不足以容纳原类型的所有可能值时)unsigned int
· 将 float 提升为 double
b signed 与 unsigned 之间的转换
· 对于 signed 较小类型和 unsigned 较大或相同类型,前者转换为后者
· 对于 signed 较大类型和 unsigned 较小类型,如何操作依赖于机器:
前者若能表示后者所有可能值则后者转换为前者,否则都转换为前者的 unsigned 形式
以上两种情况,负值有可能会被转换为 unsigned 导致溢出,造成意料之外的结果
② 转换为指针
ⅰ 表达式中的数组名会自动转换为指向数组首元素的指针
但以下情况除外:
a数组作为取地址操作符&的操作数
b数组作为 sizeof 操作符的操作数
c使用数组对数组的引用初始化时
ⅱ 指向任意类型对象的指针都可转换为 void* 型
ⅲ 整型常量0可转换为任意指针类型
③ bool 类型转换
ⅰ 算术值和指针值转换为 bool 型
0 → false 非0 → true
ⅱ bool 值转换为算术类型
true → 1 false → 0
④ 枚举成员转换为整型
枚举类型对象或枚举成员可自动转换为整型(具体类型依赖于机器和枚举成员最大值,但至少为int)
⑤ 转换为 const 对象
非 const 对象在初始化相关的 const 型引用时自动转换为 const
非 const 对象的地址或指向非 const 对象的指针也可转换为指向 const 对象的指针
⒉ 显式类型转换
⑴ 若可能,避免使用强制类型转换
确实需要使用时也应尽量小心
⑵ 命名的强制类型转换
① dynamic_cast
用于运行时类型识别(RTTI)
② const_cast
可以添加或去除指针、数据成员指针或引用的 const 特性
③ static_cast
ⅰ 可以显式完成编译器隐式执行的任何类型转换
因潜在精度损失产生的编译器警告会被关闭
· 可以用以避免不必要的隐式转换,如
已知 d 为 double, i 为 int, 将 i*=d; 写成 i*=static_cast<int>(d); 可省去将 i 转换为 double 这一非必要步骤
④ reinterpret_cast
为操作数的位模式提供较低层次的重新解释,结果依赖编译器和机器
任何不当使用都可能导致运行时错误
⑶ 旧式强制转换
在合法使用 static_cast 或 const_cast 的地方,提供与命名强制转换一样的功能
若两种转换均不合法,就执行 reinterpret_cast
由于不易判别每个显式转换的潜在风险,不推荐使用
Tags:cpp, 读书笔记
C++ Primer 读书笔记 – 第四章
Filed Under (新长征路上的代码) by 逆铭 on 2008-08-20 01:17
第4章 数组和指针
现代C++程序应使用vector和迭代器代替数组和指针,除非前二者不满足对效率的特殊要求
⒋⒈ 数组
⒈ 数组是由类型说明符、标识符和维度组成的复合类型,能保存一组某种类型的未命名对象
⒉ 定义和初始化
⑴ 类型说明符规定了存放于数组中元素的类型
可使用除引用外的任意类型,包括数组本身(数组的数组即多维数组)
⑵ 维数指定数组中包含的元素个数,须用值大于等于1的常量表达式定义,一经指定不可改变
⑶ 可以使用初值列表(用花括号括起的一组用逗号分隔的初值,可为空)显式提供元素的初值
① 此时可不指定维数,数组长度将由初值列表中的元素个数自动确定
② 若指定维数:
ⅰ 维数值不能小于初值个数
ⅱ 若维数值大于初始化列表中提供的元素个数,则只用初值列表初始化数组中前面对应的元素
其余元素,若为内置类型则初始化为0,若为类类型则调用默认构造函数
③ 对于多维数组,除第一维外其余维数都须显示指定
初值列表可内嵌花括号以指明各初值对应的位置,若不使用内嵌花括号则依次初始化
⑷ 若未提供初值列表,则数组元素像普通变量一样初始化
⑸ 使用字符串字面值初始化字符数组时注意前者结尾隐含的空字符
⒊ 不允许数组直接复制和赋值
⒋ 数组元素可通过下标操作符[]访问,下标从0开始
下标越界将导致运行时错误
⒋⒉ 指针
⒈ 指针是一种能储存对象地址的对象
⒉ 定义和初始化
⑴ 形式: 类型名* 标识符;
类型名指定指针指向对象的类型(类型名为 void 时指针可指向任意类型的对象)
① 连续声明多个指针时,每个标识符前都要加*号
② 可以连续使用多个星号*表示指向指针的指针
③ const 限定符
ⅰ 指向 const 对象的指针
a形式: const 类型名* 标识符;
(或 类型名 const* 标识符;)
b const 对象只能与这种指针关联
c不能通过这种指针修改所指对象,无论所指是否为 const
由于有此特性,该种指针常用作函数形参以防止所指对象被意外修改
ⅱ const 指针
a形式:类型名* const 标识符
b指针本身的值不能修改,即不能改变指向,但可以改变所指对象的值
ⅲ 指向 const 对象的 const 指针
a形式: const 类型名* const 标识符
b既不能改变所指对象的值,也不能改变指向
ⅳ typedef T* pT; 则 const pT t 和 pT const t 均与 T* const t 等价
④ 指向数组的指针
ⅰ 形式: 类型名 (*标识符)[维数][维数]..[维数];
ⅱ typedef 类型名新类型名[维数][维数]..[维数];
得到数组类型的别名,可以此简化定义
⑵ 应避免使用未初始化的指针
而一个有效的指针必然为以下三种状态之一:
① 保存某确定对象的地址
② 指向一个对象的下一位置
③ 值为0
因此在对指针初始化和赋值时只能使用:
① 值为0的常量表达式
② 类型匹配的对象的地址(使用取地址操作符&获得,该运算符只能对左值使用)
③ 另一对象下一位置的地址
④ 同类型另一有效指针
⒊ 指针操作
⑴ 使用解引用操作符*可以获得指针指向对象的左值,从而操作所指对象
而对指针直接进行赋值等操作将改变指针本身的值,使指针指向另一对象
⑵ 指针可被当作数组的迭代器,用以访问数组元素
① 指针的算术操作
ⅰ 指针与整型值相加(减),得到指向所指元素向后(前)移动相应位置的数组元素的新指针
ⅱ 两个指向同一数组中元素的指针(含超出末端指针)相减,得到一个 ptrdiff_t 型(定义在头文件 cstddef 中, signed 整型)结果,表示两指针所指元素间的距离
② 对指针进行下标操作[],返回所指元素向后(前)移动相应位置的数组元素引用
③ 可以计算超出末端指针,但不允许对其进行解引用操作
计算越界指针也是非法的
⑶ void* 指针不支持以上操作
⒋⒊ C风格字符串
⒈ C风格字符串是以空字符结尾的字符数组
字符串字面值就是其实例
⒉ C风格字符串的标准库函数(头文件 cstring)
传给以下库函数的须为指向以空字符结尾的字符数组的非零指针
⑴ size_t strlen( char *str );
返回字符串长度(不包括结尾的空字符)
⑵ int strcmp( const char *str1, const char *str2 );
比较两个字符串,如果前者大于后者返回正数,小于返回负数,等于返回0
注:不能使用>,<,==操作符比较,它们只会比较存放地址而不会比较字符串
⑶ char *strcat( char *str1, const char *str2 );
将str2连接到str1后面,并返回str1
此函数不进行越界检查
⑷ char *strcpy( char *to, const char *from );
将str2复制到str1字符串,并返回str1
此函数不进行越界检查
⑸ char *strncat( char *str1, const char *str2, size_t count );
将str2的前至多count个字符连接到str1后面,并返回str1
如果越界则截断字符串,因此比strcat安全
⑹ char *strncpy( char *to, const char *from, size_t count );
将str2的前至多count个字符复制到str1,并返回str1
如果越界则截断字符串,因此比strcpy安全
⒊ 对于大部分程序而言,标准库类型 string 无论安全性还是效率均强过C风格字符串,因此应尽可能使用 string
Tags:cpp, 读书笔记
C++ Primer 读书笔记 – 第三章
Filed Under (新长征路上的代码) by 逆铭 on 2008-08-12 23:05
第3章 标准库类型
⒊⒌ 标准库bitset类型
[以下下标和位数均为 size_t 型(定义在头文件 cstddef 中, unsigned 整型)]
⒈ bitset 是一种类模板,用于保存位集,并提供测位和置位操作
⒉ 定义和初始化
bitset 在定义时需要以常量表达式的形式提供位数N
初始化时参数提供位数不足则剩余高阶位置为0,位数过多则抛弃多余高阶位
⑴ bitset<N> b;
默认构造函数置各位为0
⑵ bitset<N> b( unsigned long u );
使用 unsigned long 值u的二进制形式初始化
⑶ bitset<N> b( string s, size_t pos=0 );
bitset<N> b( string s, size_t pos, size_t m );
使用 string 对象s或其(下标pos起到结尾或长度为m的)子串初始化
(子)串最右端对应低阶(low-order)位,向左依次类推
⒊ 操作
除支持所有内置位运算符以及==和!=外,还支持以下操作:
⑴ 访问整个 bitset 对象
① bool any();
返回是否各位不全为0
② bool none();
返回是否各位全为0
③ size_t count();
返回为1的位的个数
④ size_t size();
返回能容纳的位数
⑵ 访问 bitset 对象中的位
(从低阶位起,各位编号依次为 0, 1, 2, 3 …)
① 下标操作符[]返回指定位的引用
② bool test( size_t pos );
返回指定位的值
③ bitset<N>& set( size_t pos, int val=1 );
设定指定位的值并返回对象的引用
④ bitset<N>& reset( size_t pos );
清零指定位并返回对象的引用
⑤ bitset<N>& flip( size_t pos );
取反特定位并返回对象的引用
也可以b[pos].flip(),返回指定位的引用
⑶ 设置整个 bitset 对象
① bitset<N>& set();
置所有位为1并返回对象的引用
② bitset<N>& reset();
清零所有位并返回对象的引用
③ bitset<N>& flip();
取反所有位并返回对象的引用
⑷ 获取 bitset 对象的值
① unsigned long to_ulong();
返回位模式相同的 unsigned long 值
若越界则产生运行时异常
② string to_string();
返回字符串形式
③ 可使用输出操作符打印 bitset 对象
Tags:cpp, 读书笔记
C++ Primer 读书笔记 – 第二章
Filed Under (新长征路上的代码) by 逆铭 on 2008-08-07 23:06
[笔记索引]
第2章 变量和基本类型
⒉⒈ 基本内置类型
⒈ 算数类型(arithmetic types):表示数值(即整数和浮点数)的类型
⒉⒈⒈ 整型
⒈ 整型(Integral Types):表示整数、字符和布尔值的算数类型。包括:
⑴ char: 字符型,通常单个机器字节,最小8位
wchar_t:
宽字符型,最小16位
用于扩展字符集,如汉字和日语
⑵ short:
短整型,通常半个字长,最小16位
由于范围较小容易越界,执行整型算数运算时很少使用
int:
整型,通常1个字长,最小16位,大多数机器使用32位表示
用于整型运算时不易出错
long:
长整型,通常1或2个机器字长,最小32位
对用32位表示 int 而用64位表示 long 的机器,后者代价远高于前者,使用时如何选择应视情况而定
⑶ bool:
布尔型,赋值时0值算数类型为 false, 其余为 true
⒉ 带符号(signed)和无符号(unsigned)类型
⑴ 带符号类型可以表示正数、0和负数; 无符号只能表示非负数
⑵ int,short,long 都默认为 signed
⑶ char 有3种不同类型: 普通, unsigned, signed, 但只有2种表示方式
char 使用哪一种表示方式由编译器决定
⒊ 整型值的表示
⑴ unsigned 型中,所有位都用来表示数值
⑵ signed 型如何用位由编译器决定。常见策略为使用其中一个位作符号位,该位为1则值为负,为0则值为0或正
⒋ 将一个越界值赋给一个指定类型的变量时:
⑴ 若类型为 unsigned, 编译器通过对越界值取模来满足要求
⑵ 若类型为 signed, 行为未定义
⒉⒈⒉ 浮点型
⑴ float:
单精度浮点数,一般一个字长,最小6位有效数字
其可能的精度损失不可忽视
⑵ double:
双精度浮点数,一般两个字长,最小10位有效数字
其计算代最小8位价与 float 相当,使用它基本不会错
⑶ long double:
扩展精度浮点数,一般三或四个字长,最小10位有效数字
其提供的额外精度往往无必要,且需承担额外的运行代价
⒉⒉ 字面值常量
⒈ 整数字面值
⑴ 定义字面值整型常量可以使用十进制、八进制(以0开头表示)和十六进制(以0x或0X开头表示)中的任意一种
⑵ 默认为 int 或 long 型(值适合 int 就为 int 型,比 int 大最小8位就为 long 型)
⑶ 数值后加上后缀 U, L, UL 分别表示 unsigned, long, unsigned long
⒉ 浮点数字面值
⑴ 可以使用普通的十进制表示法或科学计数法表示。使用后者时,用E或e来标示指数
⑵ 默认为 double 型
⑶ 数值后加上后缀 F, L 分别表示 float, long double
⒊ 布尔字面值: true, false
⒋ 字符字面值
⑴ 通过用单引号引起的字符或转义字符定义
⑵ 前面加上L表示wchar_t型
⑶ C++中定义的转义字符有:
\’ 单引号
\” 双引号
\\ 反斜杠
\0 空字符
\a 响铃
\b 后退
\f 走纸
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\oct 编号为oct的字符(oct表示一个八进制数,不必以0开头)
\xhex 编号为hex的字符(hex表示一个十六进制数,不以0x或0X开头)
⒌ 字符串字面值
⑴ 通过用双引号引起的若干个字符或转义字符定义
⑵ 类型为以 NULL 结束的 const char 型数组(结尾的空字符由编译器自动添加)
⑶ 前面加上L表示宽字符串面值
⑷ 两个相邻的仅由空格、制表符或换行符分开的(宽)字符串面值,可连接成一个新(宽)字符串字面值
这一特性可用于处理长字符串字面值
试图连接一个字符串字面值和一个宽字符串字面值将导致未定义行为
⑸ C++代码中,在一行末尾加反斜线符号(其后不可再出现空格或注释)可将该行与下一行当作同一行处理(因此第二行可能不允许有正常的缩进)
这一特性也可用于处理长字符串字面值,但并不常用
⒉⒊ 变量
⒈ 左值(lvalue)和右值(rvalue)
⑴ 左值:可以出现在赋值操作的左边或右边的值。非 const 左值可读可写。
⑵ 右值:可以出现在赋值操作右边但不能出现在左边的值。可读不可写。
变量是左值
⒉ 变量名,可由字母或下划线开头,用字母、数字和下划线组成;大小写敏感
⒊ 变量的定义
⑴ 变量的定义为变量分配存储空间,还能同时指定其初始值。在程序中,一个变量有且仅有一个定义
⑵ 变量的初始化
① 提供初始化式时,支持两种初始化形式:
a. 复制初始化:用等号(=) (注:不是赋值)
b. 直接初始化:将初始化式放在括号中;更灵活,效率更高
对内置类型而言,二者几乎没有差别;对类类型而言,有时必须用后者
② 不提供初始化式:
a. 对内置类型变量:在函数体外定义的自动初始化为0,在函数体内定义的不进行自动初始化
b. 对类类型变量:若该类提供默认构造函数则调用它,否则必须提供显式初始化式
③ 同时定义多个变量时,以上各种初始化形式(包括不提供初始化式)都可混用;可以用同一定义中前面已定义变量的值给后面的变量初始化
⑶ 在变量首次使用处定义变量往往能增加代码可读性,减少开销
⒋ 变量的声明
⑴ 变量的声明向程序表明变量的类型和名字。声明可以在程序中出现多次。定义也是声明
⑵ 使用 extern 关键字可声明一个变量而不定义它,常用于使数据横跨多个文件的作用域
⑶ 若声明有初始化式,则被当作定义,即使使用了 extern 关键字也一样
⑷ 在全局作用域中定义的非 const 对象在整个程序的各个文件中都可见,只要在其它文件中声明它就可以访问;
但全局作用域中的 const 对象默认为其定义所在文件的局部对象,只有在定义前指定它为 extern 才能在其它文件中访问
⒉⒊⒍ 名字的作用域
⒈ 作用域(scope):程序的一部分,名字在其中有意义。
C++中的作用域有以下几种:
⑴ 全局:名字定义在任何其他作用域外
⑵ 类:名字由类定义
⑶ 命名空间:名字在命名空间中定义
⑷ 局部:名字在函数中定义
⑸ 块:名字定义在语句块中(即定义在一对花括号里)
⑹ 语句:名字在语句(如 if 、 while 、 for 语句)的条件内定义
⒉ 作用域可嵌套,外层作用域的名字在内层可见。内层作用域中的名字可以屏蔽(hide)外层中同样的
⒉⒌ 引用
⒈ 引用(reference)是一种复合类型(即用其它类型定义的类型),表示另一个(非引用)对象的别名,对它的所有操作都直接作用在该对象上
引用主要用作函数形参
⒉ 引用定义格式为
类型名& 标识符
( 数组的引用定义格式: 类型名 (&标识符)[维度]
指针的引用定义格式: 类型名*& 标识符 )
同时定义多个引用时每个引用的标识符前都要加&(以及[维度]和*)
定义引用必须用对应类型的对象初始化,表示绑定到该对象,且一经绑定不可更改
⒊ const 引用是只读的,可以绑定到不同但相关类型的对象,也可绑定到右值;
非 const 对象只能绑定到与该引用同类型的对象
⒉⒍ 定义类型名
⒈ typedef 用于定义一个类型的同义词。定义格式为:
typedef 类型 标识符;
⒉ 常为以下3种目的使用 typedef :
⑴ 隐藏特定类型实现,强调使用类型的目的
⑵ 精简类型定义以便理解
⑶ 多次使用同一类型,保持每次使用目的明确
⒉⒎ 枚举
⒈ 枚举(enumeration)类型由一组枚举成员(enumerator)组成
其中每个枚举成员都有自己的名字,初始化为整型 const 值(值可重复,但初始化后不能修改)
⒉ 定义格式: enum 枚举类型名 {用逗号分开的枚举成员列表};
可以用常量表达式通过赋值操作符为列表中某些枚举成员提供初始值,未提供初值的默认每个值比前一个大1(第一个默认为0)
⒊ 每个 enum 都唯一定义一种类型,枚举类型的对象初始化或赋值时只能通过该类型的枚举成员或另一对象进行
⒉⒐ 头文件
⒈ 因为头文件包含在多个源文件中,故一般只应包含对象和函数的声明而不包含定义,但以下除外:
⑴ 类
⑵ 用常量表达式初始化的 const 对象
(若不是用常量表达式初始化,则应和其它对象一样在一个文件中定义并初始化,并在头文件中添加 extern 声明以便多文件共享)
⑶ inline 函数
以上都可以在多个文件中定义(只要定义一致)。需要在头文件定义是因为编译器需要它们的定义来产生代码
⒉ 预处理器
⑴ #include 只接受一个头文件名作为参数
头文件名在尖括号中被认为是标准头文件,编译器将在预定义位置查找
头文件名在引号中被认为是非系统头文件,通常在源文件所在位置查找
⑵ 可使用预处理器定义头文件保护符(header guard)避免多重包含,如:
#ifndef XXX_HEADER_H
#define XXX_HEADER_H
// 头文件内容,包括类等的定义
#endif
Tags:cpp, 读书笔记
C++ Primer 读书笔记 – 索引
Filed Under (新长征路上的代码) by 逆铭 on 2008-08-07 09:31

终于开始读第二遍了……开始真没把这书当回事。搞OI的时候一直是用 C++ 的(当然是作为 a better C ……当然不包括STL……),C++ 的教材也读过(顺便Orz下谭老师),觉得写程序就是算法比较麻烦,语言只是个基础,随随便便就搞定了。这书是年初买的,当时还想着一个月看完呢,结果,呃,断断续续拖了仨月到高考前才看完第一遍。C++ 里各种各样的功能及细节一时让我觉得自己在备考地理历史或是别的什么文科课程……
这本书我觉得和CLRS很像。书名都非常谦虚(一个叫 Primer 一个叫 Introduction),都比书名暗示的要厚、难,虽然没有特别 tricky 的内容却贵在全面,如果能够掌握对付一般情况都绰绰有余。
在读第一遍的时候我就已经做了比较粗略的笔记,现在重新整理一下。所有帮助理解的辅助内容都尽量被剔除,为了帮助理解而做的顺序调整也被恢复,使得关键点以更结构化的形式组织起来。我希望有了整理的笔记就可以抛开原书(去BUAA实在不想带这书,太沉了- -)。
笔记中很多基础点可能会因为之前就已经熟知而被忽略。这个笔记并不适合初学者。它适合:
1. 我自己——这是做笔记的主要目的
2. 看过全书希望迅速浏览各个关键点来复习的同学
3. 已经读过别的 C++ 书籍不知道此书是否还值得一读的同学
4. 希望能借助别人的笔记加工出自己的
………………
恩……笔记会以章为单位放出,已经放出的内容也可能被修改。如果发现任何错误、遗漏、啰嗦等不妥的地方,欢迎指正。
笔记会放在新分类“新长征路上的代码”中。之前关于OI的分类不再更新。
———————————菜菜的分割线———————————
笔记索引 第二章 - 基本内置类型字面值常量变量作用域引用(包括指针的引用、数组的引用) 枚举 第三章 - bitset (vector、string和迭代器放到第九章和第十一章) 第四章 - 数组(动态数组放到第五章new和delete表达式部分) C风格字符串 指针(包括指向数组的指针,不包括第七章的函数指针) 第五章 - 操作符(结合性、优先级)(不包括与作用域,RTTI,成员指针,异常等有关操作符) 表达式 类型转换(显式、隐式) 第六章 - 语句(与异常处理有关的内容放到第十七章;不包括第七章return语句) 使用预处理器调试 第七章 - 函数(类成员函数放到第十二章) 第八章 - 标准IO库(包括附录3中的所有内容) (停止更新)
Tags:cpp, 读书笔记

