CPrimer 中文版第四版学习笔记.docx
《CPrimer 中文版第四版学习笔记.docx》由会员分享,可在线阅读,更多相关《CPrimer 中文版第四版学习笔记.docx(24页珍藏版)》请在冰点文库上搜索。
CPrimer中文版第四版学习笔记
C++Primer+中文版(第四版)学习笔记.txt不要放弃自己!
-------(妈妈曾经这样对我说,转身出门的一刹那,我泪流满面,却不想让任何人看见!
)看到这一句小编也心有感触,想起当初离家前往几千里外的地方的时候,妈妈也说过类似的话,但是身为男儿,必须创出一片天,才能报答父母的养育之恩!
!
C++Primer中文版(第四版)学习笔记
第一章快速入门
1.每个C++程序都包含一个或多个函数,而且必须有一个命名为main。
函数由执行函数功能的语句序列组成;
2.main函数是唯一被操作系统显式调用的函数;
3.main函数的形参个数是有限的
4.函数体是函数定义的最后部分,是以花括号开始并以花括号结束的语句块;
5.注释不会增加可执行程序的大小,编译器会忽略所有注释;
6.我们注释的风格是在注释的每一行以星号开始,指明整个范围是多行注释的一部分;
7.我们倾向于吧确定函数边界的花括号自成一行,且缩进复合的输入或输出表达式从而使操作符排列整齐;
8.标准库的头文件用尖括号<>括起来,非标准库的头文件用双引号“”括起来;
第一部分基本语言
第二章变量和基本类型
1.wchar_t类型用于扩展字符集,比如汉字和日语,这些字符集中的一些字符不能用单个char表示;
2.在位这一级上,存储器是没有结构和意义的;让存储具有结构的最基本方法是用块处理存储;
3.建议:
使用内置算术类型;
4.只有内置类型存在字面值,没有类类型的字面值,也没有任何标准库类型的字面值;
5.没有short类型的字面值常量;
6.不可打印字符和特殊字符都用转义字符书写,转义字符都以反斜线符号开始;
7.未定义行为源于编译器不能检测到的程序错误或太麻烦一直无法检测的错误;
8.C++是一门静态类型语言,在编译时会做类型检查;
9.左值可以出现在赋值语句的左边或右边,右值只能出现在的赋值语句的右边;
10.变量是左值,数字字面值是右值;
11.对象就是内存中具有类型的区域;
12.标识符不能包含两个连续的下划线,也不能以下划线开头后面紧跟一个大写字母。
有些标识符(在函数外定义的标识符)不能以下划线开头;
13.C++支持两种初始化变量的形式:
复制初始化和直接初始化。
复制初始化语法用等号(=),直接初始化则把初始化式放在括号中;
14.初始化不是复制:
初始化指创建变量并给它赋初始值,而赋值则是擦除对象的当前值并用新值代替;
15.在函数体外定义的变量都初始化成0,在函数体里定义的内置类型变量不进行自动初始化;
16.在一个程序中,变量有且仅有一个定义,但可以声明多次。
17.定义也是声明,可以通过使用extern关键字声明变量名而不定义它。
extern声明包括对象名、对象类型和对象类型前的关键字extern,extern声明不是定义,也不能分配存储空间;
18.只有当extern声明位于函数外部时才可以含有初始化式,因为已初始化的extern声明被当作是定义,所以该变量任何随后的定义都是错误的,随后含有初始化式的extern声明也是错误的;
19.用来区分名字不同意义得上下文称为作用域,作用域是程序的一段区域;
20.一般来说,名字从其声明点开始直到其声明所在的作用域结束处都是可见的;
21.局部变量的定义会屏蔽相同名字的全局变量定义;
22.在全局作用域声明的const变量是定义该对象的文件的局部变量。
此变量只存在于那个文件中,不被其他文件访问;
23.不能定义引用类型的引用,但可以定义任何其他类型的应用;
24.引用必须用于与该引用同类型的对象初始化;
25.作用在引用上的所有操作事实上都是作用在该引用绑定的对象上;
26.初始化是指明引用指向哪个对象的唯一方法,当引用初始化后,只要该引用存在,它将绑定到初始化时指向的对象。
不可能将引用绑定到另一个对象;
27.将普通的应用绑定到const对象是不合法的;
28.非const引用只能绑定到与该引用同类型的对象,const引用则可以绑定到不同但相关的类型的对象或绑定到右值;
29.默认地,第一个枚举成员赋值为0,后面的每个枚举成员赋的值比前面的大1;
30.常量表达式是编译器在编译时就能够计算出结果的整型表达式;
31.不能改变枚举成员的值;
32.枚举成员的对象初始化或赋值,只能通过其枚举成员或同意枚举类型的其他对象来进行;
33.因为头文件包含在多个源文件中,所以不应该含有变量和函数的定义。
第三章标准库类型
1.string对象比较操作是区分大小写的,即同一个字符的大小写形式被认为是两个不同的字符;
2.一个容器中的所有对象都必须是同一种类型的;
3.所谓的“缓冲区溢出”错误就是对不存在的元素进行下标操作的结果;
4.迭代器是一种检查容器内元素并遍历元素的数据类型,因为迭代器对所有的容器都适用,现代C++程序更倾向于使用迭代器而不是下标操作访问容器元素,即使对支持下标操作的vector类型也是这样;
5.每种容器类型还定义了一种名为const_iterator的类型,该类型只能用于读取容器内元素,但不能改变其值;
6.任何改变vector长度的操作都会是以存在的迭代器失效;
7.在定义bitset时,要明确bitset含有多少位,须在尖括号内给出它的长度值;
8.从string对象读入位集的顺序是从右向左;
9.string对象和bitset对象之间是反向转化的:
string对象的最右边字符(即下标最大的那个字符)用来初始化bitset对象的低阶位(即下标为0的位)。
第四章数组和指针
1.如果没有显式提供元素初值,则数组元素会像普通变量一样初始化:
在函数体外定义的内指数组,其元素均初始化为0;
在函数体类定义的内置数组,其元素无初始化;
不管数组在哪里定义,如果其元素为类类型,则自动调用该类的默认构造函数进行初始化;如果该类没有默认构造函数,则必须为该数组元素提供显式初始化;
2.指针是指向某种类型对象的复合数据类型,适用于数组的迭代器;
3.C++语言无法检测指针是否未被初始化,也无法区分有效地址和由指针分配到的存储空间中存放的二进制位形成的地址;
4.指针只能初始化或赋值为同类型的变量地址或另一指针;
5.C++提供了一种特殊的指针类型void*,它可以保存任何类型对象的地址;
6.void*指针只支持几种有限的操作:
与另一个指针进行比较:
向函数传递void*指针或从函数返回void*指针;给另一个void*指针赋值;不允许使用void*指针操纵它所指向的对象;
7.允许把非const对象的地址赋给指向const对象的指针;
8.可以修改const指针所指向的值,不能保证指向const的指针所指对象的值一定不能修改;
9.可以把指向const的指针理解为“自以为指向const的指针”;
10.任何企图给const指针赋值的行为(即使给原指针赴会同样的值)都会导致编译时的错误;
11.C风格字符串是以空字符null结束的字符数组;
12.与数组变量不同,动态分配的数组将一直存在,直到程序显式释放它为止;
13.每一个程序在执行时都占有一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区或堆;
14.可以使用跟在数组长度后面的一对空圆括号,对动态分配的数组元素做值初始化;
15.如果我们在自由存储区中创建的数组存储了内置类型的const对象,则必须为这个数组提供初始化,唯一的方法是对数组做值初始化;
16.C++允许定义类类型的const数组,但该类类型必须提供默认构造函数;
17.调用new动态创建长度为0的数组是合法的;
18.可使用C风格字符串对string对象进行初始化或赋值;
string类型的加法操作需要两个操作数,可以使用C风格字符串作为其中的一个操作数,也允许将C分隔字符串用作复合赋值的右操作数;
在要求C风格字符串的地方不可直接使用标准库string类型对象;
19.严格来讲,C++中没有**数组,通常所指的**数组其实就是数组的数组;
20.如果表达式只提供了一个下标,则结果获取的元素是该行下标索引的内层数组;
第五章表达式
1.短路求值:
逻辑与和逻辑或操作符总是先计算其左操作数,然后再计算其右操作数。
只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数;
2.赋值操作符的左操作数必须是非const的左值;
3.数组名是不可修改的左值:
因此数组不可用作赋值操作的目标;
4.只要被赋值的每个操作数都具有相同的通用类型,C++语言允许将这多个赋值操作写在一个表达式中:
intival,jval;
ival=jval=0;
5.将sizeof用于表达式expr是,没有计算表达式expr的值。
特别是在sizeof*p中,指针p可以持有一个无效地址,因为不需要对p做解引用操作;
6.C++保证:
删除0值得指针是安全的;
7.动态创建的const对象必须在创建时初始化,并且一经初始化,其值就不能再修改;
8.用作条件的表达式被转换为bool类型;
9.用一表达式初始化某个变量,或将一个表达式赋值给某个变量,则该表达式被转换为该变量的类型;
10.数组用作取地址&操作符的操作数或sizeof操作符的操作数时,或用数组对数组的引用进行初始化时,不会将数组转换为指针;
11.指向任意数据类型的指针都可转换为void*类型,整形数值常量0可转换为任意指针类型;
12.C++自动将枚举类型的对象或枚举成员转换为整形,其转换结果可用于任何要求使用整数值的地方;
13.当使用非const对象初始化const对象的引用时,系统将非const对象转换为const对象。
此外,还可以将非const对象的地址(或非const指针)转换为指向相关const类型的指针;
14.将istream类型转换为bool类型意味着要检验流的状态;
15.命名的强制类型转换符号的一般形式如下:
cast-name(expression);
其中cast-name为static_cast、dynamic_cast、const_cast和reinterpret_cast之一,type为转换的目标类型,而expression则是被强制转换的值;
16.编译器隐式执行任何类型转换都可以有static_cast显示完成;
第六章语句
1.复合语句,通常被称为块,是用一对花括号括起来的语句序列(也可能是空的);
2.else分支只能后接单个语句;
3.IO类型可以用作条件,但vector类型和string类型一般不可用作条件;
4.将else匹配给最后出现的尚未匹配的if子句来解决悬垂else问题带来的二义性;
5.每个case标号的值都必须是一个常量表达式
6.在循环条件中定义的变量在每次循环里都要经历创建和撤销的过程;
7.在for语句头定义的任何对象只限制在for循环体里可见;
8.可以在for语句的初始化语句中定义多个对象,但是不管怎么样,该处只能出现一个语句,因此所有的对象必须具有相同的一般类型;
9.break只能出现在循环或switch结构中,或者出现在嵌套于循环或switch结构中的语句里;
10.continue语句导致最近的循环语句的单次迭代提前结束,对于while和dowhile语句,继续求解循环条件,而对于for循环,程序流程接着求解for语句头中的expression表达式;
11.goto语句和获得所转移的控制权的带标号的语句必须位于同一个函数内;
12.goto语句不能跨越变量定义语句向前跳转;
第七章函数
1.在函数体类定义的变量只有在该函数中才可以访问,这种变量称为局部变量;
2.实参必须具有与形参类型相同、或者能隐式转换为形参类型的数据类型;
3.在定义或声明函数时,没有显式指定返回类型是不合法的;
4.如果两个参数具有相同的类型,则其类型必须重复声明;
5.参数表中不能出现同名的参数,局部于函数的变量也不能使用与函数任意参数相同的名字;
6.每次调用函数时,都会重新创建该函数所有的形参,此时所传递的实参将会初始化对应的形参;
7.普通的非引用类型的参数通过复制对应的实参实现初始化;
8.如果使用引用实参的唯一目的是避免复制实参,则应将形参定义为const引用;
9.非const引用形参只能与完全同类型的非const对象关联;
10.当编译器检查数组形参关联的实参时,它只会检查实参是不是指针、指针的类型和数组元素的类型是否匹配,而不会检查数组的长度;
11.在无法列举出传递给函数的所有实参的类型和数目时,可以使用省略符形参。
省略符暂停了类型检查机制。
它们的出现告知编译器,但调用函数时,可以有0或多个实参,而实参的类型未知;
12.允许主函数main没有返回值就可结束。
如果程序控制执行到主函数main的最后一个语句后都还没有返回,那么编译器会隐式地插入返回0的语句;
13.千万不能返回局部变量的引用;
14.千万不要返回指向局部对象的指针;
15.定义函数的源文件应包含声明该函数的头文件;
16.如果有一个形参拥有默认实参,那么,它后面所有的形参都必须有默认实参;
17.既可以在函数声明也可以在函数定义中指定默认实参。
但是,在一个文件中,只能为一个形参指定默认实参一次;
18.内联函数应该在头文件中定义;
19.在头文件中加入或修改内联函数时,使用了该头文件的所有源文件都必须重新编译;
20.类的成员函数都必须在类定义中的花括号里面声明,此后,就不能再为类增加任何成员;
21.编译器隐式地将在类内定义的成员函数当作内联函数;
22.每个成员函数都有一个额外的、隐含的形参this(除了static成员函数以外)。
在调用成员函数时,形参this初始化为调用函数的对象的地址;
23.在函数的形参表中包含this指针是非法的;
24.如果函数被声明为const成员函数,那么函数定义时形参表后面也必须有const;
25.构造函数和类同名,而且没有返回类型;
26.一个类可以有多个构造函数,每个构造函数必须有与其他构造函数不同数目或类型的形参;
27.如果没有为一个类显示定义任何构造函数,编译器将自动为这个类生成默认构造函数;
28.合成的默认构造函数不会自动初始化内置类型的成员;
29.main函数不能重载;
30.函数不能仅仅基于不同的返回类型而实现重载;
31.在C++中,名字查找发生在类型检查之前;
32.函数指针只能通过同类型的函数或函数指针或0值常量表达式进行初始化或赋值;
33.将函数指针初始化为0,表示该指针不指向任何函数;
34.函数的形参可以是指向函数的指针;
35.允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,而不能是函数。
第八章标准IO库
1.iostream定义读写控制窗口的类型,fstream定义读写已命名文件的类型,而sstream所定义的类型则用于读写存储在内存中的string对象;
2.如果函数有基类类型的引用形参时,可以给传递其派生类型的对象;
3.只有支持赋值的元素类型可以存储在vector或其他容器类型里,因此不存在存储流对象的vector或其他容器;
4.形参或返回类型也不能为流类型。
如果需要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用;
5.为了确保用户看到程序实际上处理的所有输出,最好的方法是保证所有的输出操作都显式地调用了flush或endl;
6.当输入流和输出流绑定在一起时,任何读输入流的尝试都将首先刷新其输出流关联的缓冲区;
7.如果在调用tie函数时传递实参0,则打破该流上已存在的捆绑;
8.关闭流并不能改变流对象的内部状态;
第二部分容器和算法
第九章顺序容器
1.顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定;
2.将一个容器复制给另一个容器时,类型必须匹配:
容器类型和元素类型都必须相同;
3.容器元素类型必须满足以下两个约束:
元素类型必须支持赋值运算;
元素类型的对象必须可以复制;
4.除了引用类型外,所有内置或复合类型都可用做元素类型;
5.IO库类型不支持复制和赋值,因此不能创建存放IO类型对象的容器;
6.定义元素是容器的容器时,必须用空格隔开两个相邻的>符号,以示这是两个分开的符号,否则,系统会认为>>是单个符号,为右移操作符,并结果导致编译时错误;
example:
vector>lines;
7.==和!
=这两种关系运算适用所有容器;
8.关系操作符只适用于vector和deque的容器,这是因为只有这两种容器元素提供快速、随机的访问。
它们确保可根据元素位置直接有效地访问指定容器元素;
9.C++语言使用一对迭代器标记迭代器范围,这两个迭代器分别指向同一个容器中的两个元素或超出末端的下一位置;
10.所有顺序容器都支持push_back操作,提供在容器尾部插入一个元素的功能;
11.为了避免存储end迭代器,可以在每次做完插入运算后重新计算end迭代器;
12.比较的容器必须具有相同的容器类型,而且其元素类型也必须相同;
13.C++语言只允许两个容器做其元素类型定义的关系运算;
14.对于所有的容器类型,如果resize操作压缩了容器,则指向已删除的元素的迭代器失效;
15.寻找一个指定元素的最简单方法是使用标准库的find算法;
16.erase、pop_front和pop_back函数通常使指向被删除元素的所有迭代器失效。
对于vector容器,指向删除点后面的元素的迭代器通常也会失效。
而对于deque容器,如果删除时不包含第一个元素和最后一个元素,那么读deque容器相关的所有迭代器都会失效;
17.swap操作则不会使迭代器失效。
完成swap操作后,尽管被交换的元素已经存放在另一容器中,但迭代器仍然指向相同的元素;
18.要交换的容器的类型必须匹配:
操作数必须是相同类型的容器,而且所储存的元素类型也必须相同;
19.对于大部分应用,使用vector容器时最好的,原因在于,标准库的实现者使用这样的内存分配策略:
以最小的代价连续存储元素,由此而带来的访问元素的便利弥补了其存储代价;
20.每当vector容器不得不分配新的存储空间时,以加倍当前容量的分配策略实现重新分配;
21.string类型不支持以栈方式操纵容器;
22.无论要求赋值多少个字符,标准库最多只能复制数目与string对象长度相等的字符;
23.stack适配器可以建立在vector、list或者deque容器之上,queue适配器只能建立在list容器上,priority_queue适配器只能建立在vector或deque容器上;
第十章关联容器
1.关联容器支持通过键来高效地查找和读取元素;
2.关联容器不提供front、push_front、pop_front、back、push_back以及pop_back操作;
3.要使用map对象,则必须包含map头文件;
4.所有的比较函数必须在键类型上定义严格弱排序;
5.在实际应用中,键类型必须定义<操作符,而且该操作符应能“正确地工作”;
6.使用下标访问map中不存在的元素将导致在map容器中添加一个新的元素,它的键即为该下标值;
7.map容器和set容器一样,存储的键必须唯一,而且不能修改(键的类型均为const);
8.multimap不支持下标运算;
第十一章泛型算法
1.使用泛型算法必须包含algorithm头文件;
2.标准库还定义了一组泛化的算术算法,其命名习惯与泛型算法相同,使用这些算法必须包含numeric头文件;
3.使用插入迭代器back_inserter的程序必须包含iterator头文件;
4.通常,如果要以一个已存在的容器为副本创建新容器,更好的方法是直接用输入范围作为性构造容器的初始化式;
5.算法不直接修改容器的大小,如果需要添加和删除元素,则必须使用容器操作;
6.谓词是做某些检测的函数,返回用于条件判断的类型,指出条件是否成立;
7.流迭代器值定义了最基本的迭代器操作:
自增、解引用和赋值。
此外,可比较两个istream迭代器是否相等;而ostream迭代器则不通过比较运算;
8.流迭代器不能创建反向迭代器;
9.需要低级类别迭代器的地方,可以使用任意一种更高级的迭代器;
第三部分类和数据抽象
第十二章类
1.将关键字const家在形参表之后,就可以将成员函数声明为常量:
doubleavg_price()const;
const成员不能改变其所操作对象的数据成员,const必须同时出现在声明和定义中,若只出现在其中一处,就会出现一个编译时错误;
2.类背后蕴涵的基本思想是数据抽象和封装;
3.在const成员函数中,this的类型是一个指向const类类型对象的const指针。
既不能改变this所指向的对象,也不能改变this所保存的地址;
4.不能从const成员函数返回指向类对象的普通引用。
Const成员函数只能返回*this作为一个const引用;
5.可以通过声明为mutable来实现对类的数据成员的修改(甚至在const成员函数内),将关键字mutable放在成员声明之前:
mutablesize_taccess_ctr;
6.可变数据成员永远都不能为const,甚至当它是const对象的成员时也如此,因此const成员函数可以改变mutable成员;
7.即使两个类具有完全相同的成员列表,它们也是不同的类型。
每个类的成员不同于任何其他类(或任何其他作用域)的成员;
8.在类作用域之外,成员只能通过对象或指针分别使用成员访问操作符.或->来访问;
9.出现在类的定义体之外的成员定义必须指明成员出现在那个类中:
doubleSales_item:
:
avg_price()const
{……}
10.在定义于类外部的成员函数中,形参表和成员函数体出现在成员名之后,这些都是在类作用域中定义,所以可以不用限定而引用其他成员;
11.返回类型出现在成员名字前面,如果函数在类定义体之外定义,则用于返回类型的名字在类作用域之外,如果返回类型使用由类定义的类型,则必须使用完全限定名;
12.类定义实际上式在两个阶段中处理:
首先,编译成员声明;
只有在所有成员出现之后,才编译它们的定义本身;
13.类成员定义中的查找:
首先检查成员函数局部作用域中的声明;
如果在成员函数中找不到该名字的声明,则检查对所有类成员的声明;
如果在类中找不到该名字的声明,则检查在此成员函数定义之前的作用域中出现的声明;
14.使用相同名字来表示形参和成员,可能导致类的成员被屏蔽,但是仍然可以通过用类名来限定成员名或显式使用this指针使用它;
15.构造函数初始化式只在构造函数的定义中而不是声明中指定;
16.省略初始化列表并在构造函数的函数体