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声明包括对象名、对象类型和对象类型前的关键字externextern声明不是定义,也不能分配存储空间;

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++语言允许将这多个赋值操作写在一个表达式中:

int ivaljval

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<type>(expression)

其中cast-namestatic_cast dynamic_cast const_castreinterpret_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语句导致最近的循环语句的单次迭代提前结束,对于whiledo while语句,继续求解循环条件,而对于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.       为了确保用户看到程序实际上处理的所有输出,最好的方法是保证所有的输出操作都显式地调用了flushendl

6.       当输入流和输出流绑定在一起时,任何读输入流的尝试都将首先刷新其输出流关联的缓冲区;

7.       如果在调用tie函数时传递实参0,则打破该流上已存在的捆绑;

8.       关闭流并不能改变流对象的内部状态;

 

 

第二部分 容器和算法

 

第九章 顺序容器

1.       顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定;

2.       将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同;

3.       容器元素类型必须满足以下两个约束:

元素类型必须支持赋值运算;

元素类型的对象必须可以复制;

4.       除了引用类型外,所有内置或复合类型都可用做元素类型;

5.       IO库类型不支持复制和赋值,因此不能创建存放IO类型对象的容器;

6.       定义元素是容器的容器时,必须用空格隔开两个相邻的>符号,以示这是两个分开的符号,否则,系统会认为>>是单个符号,为右移操作符,并结果导致编译时错误;

examplevector< vector<string> > lines;

7.       = = 和!=这两种关系运算适用所有容器;

8.       关系操作符只适用于vectordeque的容器,这是因为只有这两种容器元素提供快速、随机的访问。它们确保可根据元素位置直接有效地访问指定容器元素;

9.       C++语言使用一对迭代器标记迭代器范围,这两个迭代器分别指向同一个容器中的两个元素或超出末端的下一位置;

10.   所有顺序容器都支持push_back操作,提供在容器尾部插入一个元素的功能;

11.   为了避免存储end迭代器,可以在每次做完插入运算后重新计算end迭代器;

12.   比较的容器必须具有相同的容器类型,而且其元素类型也必须相同;

13.   C++语言只允许两个容器做其元素类型定义的关系运算;

14.   对于所有的容器类型,如果resize操作压缩了容器,则指向已删除的元素的迭代器失效;

15.   寻找一个指定元素的最简单方法是使用标准库的find算法;

16.   erasepop_frontpop_back函数通常使指向被删除元素的所有迭代器失效。对于vector容器,指向删除点后面的元素的迭代器通常也会失效。而对于deque容器,如果删除时不包含第一个元素和最后一个元素,那么读deque容器相关的所有迭代器都会失效;

17.   swap操作则不会使迭代器失效。完成swap操作后,尽管被交换的元素已经存放在另一容器中,但迭代器仍然指向相同的元素;

18.   要交换的容器的类型必须匹配:操作数必须是相同类型的容器,而且所储存的元素类型也必须相同;

19.   对于大部分应用,使用vector容器时最好的,原因在于,标准库的实现者使用这样的内存分配策略:以最小的代价连续存储元素,由此而带来的访问元素的便利弥补了其存储代价;

20.   每当vector容器不得不分配新的存储空间时,以加倍当前容量的分配策略实现重新分配;

21.   string类型不支持以栈方式操纵容器;

22.   无论要求赋值多少个字符,标准库最多只能复制数目与string对象长度相等的字符;

23.   stack适配器可以建立在vectorlist或者deque容器之上,queue适配器只能建立在list容器上,priority_queue适配器只能建立在vectordeque容器上;

 

 

第十章 关联容器

1.       关联容器支持通过键来高效地查找和读取元素;

2.       关联容器不提供frontpush_frontpop_frontbackpush_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家在形参表之后,就可以将成员函数声明为常量:

double avg_price()const

const成员不能改变其所操作对象的数据成员,const必须同时出现在声明和定义中,若只出现在其中一处,就会出现一个编译时错误;

2.       类背后蕴涵的基本思想是数据抽象和封装;

3.       const成员函数中,this的类型是一个指向const类类型对象的const指针。既不能改变this所指向的对象,也不能改变this所保存的地址;

4.       不能从const成员函数返回指向类对象的普通引用。Const成员函数只能返回*this作为一个const引用;

5.       可以通过声明为mutable来实现对类的数据成员的修改(甚至在const成员函数内),将关键字mutable放在成员声明之前:

mutable size_t access_ctr

6.       可变数据成员永远都不能为const,甚至当它是const对象的成员时也如此,因此const成员函数可以改变mutable成员;

7.       即使两个类具有完全相同的成员列表,它们也是不同的类型。每个类的成员不同于任何其他类(或任何其他作用域)的成员;

8.       在类作用域之外,成员只能通过对象或指针分别使用成员访问操作符 . ->来访问;

9.       出现在类的定义体之外的成员定义必须指明成员出现在那个类中:

double Sales_item::avg_price()const

{……}

10.   在定义于类外部的成员函数中,形参表和成员函数体出现在成员名之后,这些都是在类作用域中定义,所以可以不用限定而引用其他成员;

11.   返回类型出现在成员名字前面,如果函数在类定义体之外定义,则用于返回类型的名字在类作用域之外,如果返回类型使用由类定义的类型,则必须使用完全限定名;

12.   类定义实际上式在两个阶段中处理:

首先,编译成员声明;

只有在所有成员出现之后,才编译它们的定义本身;

13.   类成员定义中的查找:

首先检查成员函数局部作用域中的声明;

如果在成员函数中找不到该名字的声明,则检查对所有类成员的声明;

如果在类中找不到该名字的声明,则检查在此成员函数定义之前的作用域中出现的声明;

14.   使用相同名字来表示形参和成员,可能导致类的成员被屏蔽,但是仍然可以通过用类名来限定成员名或显式使用this指针使用它;

15.   构造函数初始化式只在构造函数的定义中而不是声明中指定;

16.   省略初始化列表并在构造函数的函数体内对数据成员赋值是合法的;

17.   没有默认构造函数的类类型成员,以及const或引用类型的成员,都必须在构造函数初始化列表中进行初始化;

18.   成员被初始化的次序就是定义成员的次序;

19.   内置和复合类型的成员,如指针和数组,只对定义在全局作用域中的对象初始化;

20.   使用默认构造函数定义一个对象的正确方式是去掉最后的空括号:

sales_item myobj();  //error ,defines a function, not an object

sales_item myob ;  // ok

21.   可以通过将构造函数声明为explicit,来防止在需要隐式转换的上下文中使用构造函数;

22.   explicit关键字只能用于类内部的构造函数声明上,在类的定义体外部所做的定义上不再重复它;

23.   友元可以使普通的非成员函数,或前面定义的其他类的成员函数,或整个类。将一个类设为友元,友元类的所有成员函数后可以访问授予友元关系的那个类的非公有成员;

24.   类必须将重载函数集中每一个希望设为友元的函数都声明为友元;

25.   可以通过作用域操作符从类直接调用static成员,或者通过对象、引用或指向该类类型对象的指针间接调用;

26.   类成员函数可以不用作用域操作符来引用类的static成员;

 

 

第十三章 复制控制

1.       复制构造函数具有单个形参,该形参(常用const修饰)是对该类类型的引用,当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数,当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式使用复制构造函数;

2.       不管类是否定义了自己的析构函数,编译器都自动执行类中非static数据成员的析构函数;

3.       不能对IO类型的对象使用复制初始化;

4.       当形参或返回值为类类型时,有复制构造函数进行赋值;

5.       即使定义了其他构造函数,也会合成赋值构造函数,合成复制构造函数的行为时,执行逐个成员初始化,将新对象初始化为原对象的副本;

6.       只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义复制构造函数,也可以复制;

7.       为了防止赋值,类必须显式声明其复制构造函数为private,然而,类的友元和成员仍可进行赋值,如果想要连友元和成员中的复制也禁止,就可以声明一个private复制构造函数但不对其定义;

8.       一般来说,最好显式或隐式定义默认构造函数和复制构造函数。只有不存在其他构造函数时才合成默认构造函数。如果定义了复制构造函数,也必须定义默认构造函数;

9.       如果类需要析构函数,则它也需要赋值操作符和复制构造函数;

10.   析构函数没有返回值,没有形参,也不能进行重载;

11.   编写自己的复制构造函数时,必须显式复制需要复制的任意成员。显式定义的复制构造函数不会进行任何自动复制;

 

 

 

 

 

 

 

第十四章 重载操作符与转换

1.       不能通过连接其他合法符号来创建任何新的操作符;

2.       用于内置类型的操作符,其含义不能改变,也不能为任何内置类型定义额外的新的操作符;

3.       操作符的优先级、结合性或操作数数目不能改变;

4.       重载逻辑操作符不再具备短路求值的特性;

5.       输入操作符必须处理错误和文件结束的可能性;

6.       一般而言,赋值操作符与复合赋值操作符应返回左操作数的引用;

7.       普通重载不能区别所定义的是前缀式操作符,为了解决这个问题,后缀式操作符函数接受一个额外的(即,无用的)int形参,使用后缀式操作符时,编译器提供0作为这个形参的实参;

CheckedPtr&  CheckedPtr::operator--();   //prefix operators

CheckedPtr&  CheckedPtr::operator--int); //postfix operators

 

8.       可以为类类型的对象重载函数调用操作符,一般为表示操作的类重载调用操作符;

struct absint{

int operator()(int val{

   return val<0 -val val

}

   }

 

9.       标准库提供了一组函数适配器,分为绑定器(bind1st bind2nd)和求反器(not1not2):

  bind1st将给定值绑定到二元函数对象的第一个实参,bind2nd将给定值绑定到二元函数对象的第二个实参;

  not1将一元函数对象的真值求反,not2将二元函数的对象的真值求反;

10.   转换操作符定义将类类型值转变为其他类型值的转换,转换操作符在类定义体内声明,必须是成员函数,并且形参表必须为空。采用如下通用形式:

operator type();

这里type表示内置类型名、类类型名或由类型别名所定义的名字。对任何可作为函数返回类型的类型(除了void之外)都可以定义转换函数。一般而言,不允许转换为数组或函数类型,转换为指针类型(数据和函数指针)以及引用类型是可以的;

11.   虽然转换函数不能指定返回类型,但是每个转换函数必须显式返回一个指定类型的值;

12.   转换函数一般不应该改变被转换对象,因此转换操作符通常应定义为const成员;

13.   类类型转换之后不能再跟另一个类类型转换,如果需要多个类类型转换,则代码将出错;

14.   既为算术类型提供转换函数,又为同一类类型提供重载操作符,可能会导致重载操作符和内置操作符之间的二义性;

 

 

 

 

 

 

 

 

第四部分 面向对象编程与泛型编程

 

第十五章 面向对象编程

1.       C++中,多态性仅用于通过继承而相关联的类型的引用和指针;

2.       除了构造函数以外,任意非static成员函数都可以是虚函数。保留字virtual只在类内部的成员函数声明中出现,不能用在类定义体外部出现的函数定义上;

3.       protected成员不能被类的用户访问,但可被类的派生类访问;

4.       派生类只能通过派生类对象访问其基类的protected成员,派生类对其基类类型对象的protected成员没有特殊访问权限;

5.       派生类的虚函数可以返回基类函数所返回类型的派生类的引用或指针;

6.       一旦函数在基类中声明为虚函数,它就一直为虚函数,派生类无法改变该函数为虚函数的这一事实;

7.       派生类对象由多个部分组成:派生类本身定义的(非static)成员加上由基类(非static)成员组成的子对象;

8.       C++语言不要求编译器将对象的基类部分和派生部分连续排列;

9.       用作基类的类必须是已定义的的;

10.   继承的分类:

如果是公用继承,基类成员保持自己的访问级别:基类的public成员为派生类的public成员,基类的protected成员为派生类的protected成员;

如果是受保护继承,基类的publicprotected成员在派生类中为protected成员;

如果是私有继承,基类的所有成员在派生类中为private成员;

11.   struct定义的类和class定义的类唯一的不同知识默认成员的保护级别和默认的派生保护级别,struct默认的具有public继承,而class则具有private继承;

12.   友元可以访问类的privateprotected数据;

13.   友元关系不能继承,基类友元关系对派生类的成员没有特殊访问权限,如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类;

14.   一般可以使用派生类型的对象对基类对象进行赋值或初始化;

15.   对基类对象进行赋值和初始化,实际上是在调用函数:初始化时定义构造函数,赋值时调用赋值操作符;

16.   如果是public继承,则用户代码和后代类都可以使用派生类到基类的转换。如果类是使用privateprotected继承派生的,则用户代码不能将派生类对象转换为基类对象。如果是private继承,则从private继承类派生的类不能转换为基类。如果是protected继承,则后续派生类的成员可以转换为基类类型;

17.   基类对象只能是基类对象,它不能包含派生类型的对象;

18.   当构造、复制、赋值和撤销派生类型对象时,也会构造、复制、赋值和撤销这些基类子对象;

19.   派生类的合成默认构造函数除了初始化派生类的数据成员之外,它还初始化派生类对象的基类部分;

20.   派生类构造函数通过将基类包含在构造函数初始化列表中来间接初始化继承成员;

21.   派生类析构函数不负责撤销基类对象的成员;

22.   与基类成员同名的派生类成员将屏蔽对基类成员的直接访问,但仍可使用作用域操作符访问被屏蔽的基类成员;

23.   在基类和派生类中使用同一个名字的成员函数,其行为与数据成员一样:在派生类作用域中派生类成员将屏蔽基类成员。即使函数原型不同,基类成员也会被屏蔽;

24.   局部作用域中声明的函数不会重载全局作用域中定义的函数,同样,派生类中定义的函数也不能重载基类中定义的成员。通过派生类对象调用函数时,实参必须与派生类中定义的版本相匹配,只有在派生类根本没有定义该函数时,才考虑基类函数;

25.   含有或继承一个或多个纯虚函数的类是抽象基类。除了作为抽象基类的派生类的对象的组成部分,不能创建抽象类型的对象;

 

第十六章  模板与泛型编程

1.       模板定义以关键字template开始,后接模板形参表,模板形参表使用尖括号括住的一个或多个模板形参的列表,形参之间以逗号分隔;

2.       模板形参表不能为空;

3.       模板形参可以是表示类型的类型形参,也可以是表示常量表达式的非类型形参;

4.       使用函数模板时,编译器会推断哪个(或哪些)模板实参绑定到模板形参。一旦编译器确定了实际的模板实参,就称它实例化了函数模板的一个实例;

5.       与全局作用域中声明的对象、函数或类型同名的模板形参会屏蔽全局名字;

6.       用作模板形参的名字不能在模板内重用,模板形参的名字只能在同一模板形参表中使用一次;

7.       模板形参的名字可以在不同模板中重用;

8.       每个模板类型形参前面必须带上关键字classtypename,每个非类型形参前面必须带上类型名字,省略关键字或类型说明符是错误的;

9.       编写泛型代码的两个重要原则:

模板的形参是const引用;

函数体中的测试只用<比较;

10.   模板编译模型分为包含编译模型和分别编译模型两种;

11.   export关键字能够指明给定的定义可能会需要在其他文件中产生实例化;

12.   类模板成员函数的定义具有如下形式:

必须以关键字template开头,后接类的模板形参表;

必须指出它是哪个类的成员;

类名必须包含其模板形参; 

   exampletemplate <class T> ret-type(返回类型)Queue<T> ::member-name

13.   在实例化类模板成员函数的时候,编译器不执行模板形参推断,相反,类模板成员函数的模板形参由调用该函数的对象的类型确定;

14.   类模板成员函数只有为程序所用才进行实例化,如果某函数从未使用,则不会实例化该成员函数;

15.   非类型模板实参必须是编译时常量表达式;

16.   在类模板中可以出现三种友元声明:

普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数;

类模板或函数模板的友元声明,授予对友元所有实例的访问权;

只授予对类模板或函数模板的特定实例的访问权的友元声明;

17.   模板特化:一个或多个模板形参的实际类型或实际值是指定的,特化的形式如下:

关键字template后面接一对空的尖括号(<  >;

再接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参;

函数形参表和函数体;

18.   对具有同一模板实参集的同一模板,程序不能既有显式特化又有实例化;

19.   特化出现在对该模板实力的调用之后是错误的;

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【原书名】 C++ Primer (4th Edition) 【原出版社】 Addison Wesley/Pearson 【作者】 (美)Stanley B.Lippman,Josée LaJoie,Barbara E.Moo 【译者】 李师贤 蒋爱军 梅晓勇 林瑛 【丛书名】 图灵计算机科学丛书 【出版社】 人民邮电出版社 【书号】 7-115-14554-7 【开本】 16开 【页码】 900 【出版日期】 2006-3-1 【版次】 4-1 【内容简介】 本书是久负盛名的C++经典教程,其内容是C++大师Stanley B. Lippman丰富的实践经验和C++标准委员会原负责人Josée Lajoie对C++标准深入理解的完美结合,已经帮助全球无数程序员学会了C++。本版对前一版进行了彻底的修订,内容经过了重新组织,更加入了C++ 先驱Barbara E. Moo在C++教学方面的真知灼见。既显著改善了可读性,又充分体现了C++语言的最新进展和当前的业界最佳实践。书中不但新增大量教学辅助内容,用于强调重要的知识点,提醒常见的错误,推荐优秀的编程实践,给出使用提示,还包含大量来自实战的示例和习题。对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使本书成为C++初学者的最佳指南;对于中高级程序员,本书也是不可或缺的参考书。本书的前言阐述了 第4版和前一版的不同之处。 【目录信息】 第1章 快速入门 1 1.1 编写简单的C++程序 2 1.2 初窥输入/输出 5 1.2.1 标准输入与输出对象 5 1.2.2 一个使用IO库的程序 5 1.3 关于注释 8 1.4 控制结构 10 1.4.1 while语句 10 1.4.2 for语句 12 1.4.3 if语句 14 1.4.4 读入未知数目的输入 15 1.5 类的简介 17 1.5.1 Sales_item类 17 1.5.2 初窥成员函数 19 1.6 C++程序 21 小结 22 术语 22 第一部分 基本语言 第2章 变量和基本类型 29 2.1 基本内置类型 30 2.1.1 整型 30 2.1.2 浮点型 32 2.2 字面值常量 34 2.3 变量 38 2.3.1 什么是变量 39 2.3.2 变量名 40 2.3.3 定义对象 42 2.3.4 变量初始化规则 44 2.3.5 声明和定义 45 2.3.6 名字的作用域 46 2.3.7 在变量使用处定义变量 48 2.4 const限定符 49 2.5 引用 50 2.6 typedef名字 53 2.7 枚举 53 2.8 类类型 54 2.9 编写自己的头文件 57 2.9.1 设计自己的头文件 58 2.9.2 预处理器的简单介绍 60 小结 62 术语 62 第3章 标准库类型 67 3.1 命名空间的using声明 68 3.2 标准库string类型 70 3.2.1 string对象的定义和初始化 70 3.2.2 String对象的读写 71 3.2.3 string对象的操作 72 3.2.4 string对象中字符的处理 76 3.3 标准库vector类型 78 3.3.1 vector对象的定义和初始化 79 3.3.2 vector对象的操作 81 3.4 迭代器简介 83 3.5 标准库bitset类型 88 3.5.1 bitset对象的定义和初始化 88 3.5.2 bitset对象上的操作 90 小结 92 术语 92 第4章 数组和指针 95 4.1 数组 96 4.1.1 数组的定义和初始化 96 4.1.2 数组操作 99 4.2 指针的引入 100 4.2.1 什么是指针 100 4.2.2 指针的定义和初始化 101 4.2.3 指针操作 104 4.2.4 使用指针访问数组元素 106 4.2.5 指针和const限定符 110 4.3 C风格字符串 113 4.3.1 创建动态数组 117 4.3.2 新旧代码的兼容 120 4.4 多维数组 122 小结 124 术语 125 第5章 表达式 127 5.1 算术操作符 129 5.2 关系操作符和逻辑操作符 131 5.3 位操作符 134 5.3.1 bitset对象或整型值的使用 135 5.3.2 将移位操作符用于IO 137 5.4 赋值操作符 137 5.4.1 赋值操作的右结合性 138 5.4.2 赋值操作具有低优先级 138 5.4.3 复合赋值操作符 139 5.5 自增和自减操作符 140 5.6 箭头操作符 142 5.7 条件操作符 143 5.8 sizeof操作符 144 5.9 逗号操作符 145 5.10 复合表达式的求值 145 5.10.1 优先级 145 5.10.2 结合性 146 5.10.3 求值顺序 148 5.11 new和delete表达式 150 5.12 类型转换 154 5.12.1 何时发生隐式类型转换 154 5.12.2 算术转换 155 5.12.3 其他隐式转换 156 5.12.4 显式转换 158 5.12.5 何时需要强制类型转换 158 5.12.6 命名的强制类型转换 158 5.12.7 旧式强制类型转换 160 小结 161 术语 162 第6章 语句 165 6.1 简单语句 166 6.2 声明语句 167 6.3 复合语句(块) 167 6.4 语句作用域 168 6.5 if语句 169 6.6 switch语句 172 6.6.1 使用switch 173 6.6.2 switch中的控制流 173 6.6.3 default标号 175 6.6.4 switch表达式与case标号 176 6.6.5 switch内部的变量定义 176 6.7 while语句 177 6.8 for循环语句 179 6.8.1 省略for语句头的某些部分 180 6.8.2 for语句头中的多个定义 181 6.9 do while语句 182 6.10 break语句 183 6.11 continue语句 184 6.12 goto语句 185 6.13 try块和异常处理 186 6.13.1 throw表达式 186 6.13.2 try块 187 6.13.3 标准异常 189 6.14 使用预处理器进行调试 190 小结 192 术语 192 第7章 函数 195 7.1 函数的定义 196 7.1.1 函数返回类型 197 7.1.2 函数形参表 198 7.2 参数传递 199 7.2.1 引用形参 199 7.2.2 引用形参 201 7.2.3 vector和其他容器类型的形参 206 7.2.4 数组形参 206 7.2.5 传递给函数的数组的处理 209 7.2.6 main:处理命令行选项 210 7.2.7 含有可变形参的函数 211 7.3 return语句 211 7.3.1 没有返回值的函数 212 7.3.2 具有返回值的函数 212 7.3.3 递归 216 7.4 函数声明 217 7.5 局部对象 220 7.5.1 自动对象 220 7.5.2 静态局部对象 220 7.6 内联函数 221 7.7 类的成员函数 222 7.7.1 定义成员函数的函数体 223 7.7.2 在类外定义成员函数 225 7.7.3 编写Sales_item类的构造 函数 225 7.7.4 类代码文件的组织 227 7.8 重载函数 228 7.8.1 重载与作用域 230 7.8.2 函数匹配与实参转换 231 7.8.3 重载确定的三个步骤 232 7.8.4 实参类型转换 234 7.9 指向函数的指针 237 小结 239 术语 240 第8章 标准IO库 243 8.1 面向对象的标准库 244 8.2 条件状态 247 8.3 输出缓冲区的管理 249 8.4 文件的输入和输出 251 8.4.1 文件流对象使用 251 8.4.2 文件模式 254 8.4.3 一个打开并检查输入文件的 程序 256 8.5 字符串流 257 小结 259 术语 259 第二部分 容器和算法 第9章 顺序容器 263 9.1 顺序容器的定义 264 9.1.1 容器元素的初始化 265 9.1.2 容器内元素的类型约束 267 9.2 迭代器和迭代器范围 268 9.2.1 迭代器范围 270 9.2.2 使迭代器失效的容器操作 271 9.3 顺序容器的操作 272 9.3.1 容器定义的类型别名 272 9.3.2 begin和end成员 273 9.3.3 在顺序容器中添加元素 273 9.3.4 关系操作符 277 9.3.5 容器大小的操作 278 9.3.6 访问元素 279 9.3.7 删除元素 280 9.3.8 赋值与swap 282 9.4 vector容器的自增长 284 9.5 容器的选用 287 9.6 再谈string类型 289 9.6.1 构造string对象的其他方法 290 9.6.2 修改string对象的其他方法 292 9.6.3 只适用于string类型的操作 293 9.6.4 string类型的查找操作 295 9.6.5 string对象的比较 298 9.7 容器适配器 300 9.7.1 栈适配器 301 9.7.2 队列和优先级队列 302 小结 303 术语 303 第10章 关联容器 305 10.1 引言:pair类型 306 10.2 关联容器 308 10.3 map类型 309 10.3.1 map对象的定义 309 10.3.2 map定义的类型 310 10.3.3 给map添加元素 311 10.3.4 使用下标访问map对象 311 10.3.5 map::insert的使用 313 10.3.6 查找并读取map中的元素 315 10.3.7 从map对象中删除元素 316 10.3.8 map对象的迭代遍历 316 10.3.9 “单词转换”map对象 317 10.4 set类型 319 10.4.1 set容器的定义和使用 319 10.4.2 创建“单词排除”集 321 10.5 multimap和multiset类型 322 10.5.1 元素的添加和删除 322 10.5.2 在multimap和multiset 中查找元素 323 10.6 容器的综合应用:文本查询程序 325 10.6.1 查询程序的设计 326 10.6.2 TextQuery类 327 10.6.3 TextQuery类的使用 328 10.6.4 编写成员函数 330 小结 332 术语 332 第11章 泛型算法 335 11.1 概述 336 11.2 初窥算法 339 11.2.1 只读算法 339 11.2.2 写容器元素的算法 341 11.2.3 对容器元素重新排序的算法 343 11.3 再谈迭代器 347 11.3.1 插入迭代器 348 11.3.2 iostream迭代器 349 11.3.3 反向迭代器 353 11.3.4 const迭代器 355 11.3.5 五种迭代器 356 11.4 泛型算法的结构 358 11.4.1 算法的形参模式 359 11.4.2 算法的命名规范 359 11.5 容器特有的算法 361 小结 362 术语 363 第三部分 类和数据抽象 第12章 类 367 12.1 类的定义和声明 368 12.1.1 类定义:扼要重述 368 12.1.2 数据抽象和封装 369 12.1.3 关于类定义的更多内容 372 12.1.4 类声明与类定义 374 12.1.5 类对象 375 12.2 隐含的this指针 376 12.3 类作用域 380 类作用域中的名字查找 382 12.4 构造函数 385 12.4.1 构造函数初始化式 387 12.4.2 默认实参与构造函数 391 12.4.3 默认构造函数 392 12.4.4 隐式类类型转换 393 12.4.5 类成员的显式初始化 396 12.5 友元 396 12.6 static类成员 398 12.6.1 static成员函数 400 12.6.2 static数据成员 400 小结 403 术语 403 第13章 复制控制 405 13.1 复制构造函数 406 13.1.1 合成的复制构造函数 409 13.1.2 定义自己的复制构造函数 409 13.1.3 禁止复制 410 13.2 赋值操作符 411 13.3 析构函数 412 13.4 消息处理示例 415 13.5 管理指针成员 419 13.5.1 定义智能指针类 421 13.5.2 定义值型类 425 小结 427 术语 427 第14章 重载操作符与转换 429 14.1 重载操作符的定义 430 14.2 输入和输出操作符 435 14.2.1 输出操作符<>的重载 437 14.3 算术操作符和关系操作符 439 14.3.1 相等操作符 440 14.3.2 关系操作符 441 14.4 赋值操作符 441 14.5 下标操作符 442 14.6 成员访问操作符 443 14.7 自增操作符和自减操作符 446 14.8 调用操作符和函数对象 449 14.8.1 将函数对象用于标准库算法 450 14.8.2 标准库定义的函数对象 451 14.8.3 函数对象的函数适配器 453 14.9 转换与类类型 454 14.9.1 转换为什么有用 454 14.9.2 转换操作符 455 14.9.3 实参匹配和转换 458 14.9.4 重载确定和类的实参 461 14.9.5 重载、转换和操作符 464 小结 466 术语 467 第四部分 面向对象编程与泛型编程 第15章 面向对象编程 471 15.1 面向对象编程:概述 472 15.2 定义基类和派生类 473 15.2.1 定义基类 474 15.2.2 protected成员 475 15.2.3 派生类 476 15.2.4 virtual与其他成员函数 479 15.2.5 公用、私有和受保护的继承 482 15.2.6 友元关系与继承 486 15.2.7 继承与静态成员 486 15.3 转换与继承 487 15.3.1 派生类到基类的转换 487 15.3.2 基类到派生类的转换 489 15.4 构造函数和复制控制 490 15.4.1 基类构造函数和复制控制 490 15.4.2 派生类构造函数 490 15.4.3 复制控制和继承 494 15.4.4 虚析构函数 495 15.4.5 构造函数和析构函数中的虚函数 497 15.5 继承情况下的类作用域 497 15.5.1 名字查找在编译时发生 498 15.5.2 名字冲突与继承 498 15.5.3 作用域与成员函数 499 15.5.4 虚函数与作用域 500 15.6 纯虚函数 502 15.7 容器与继承 503 15.8 句柄类与继承 504 15.8.1 指针型句柄 505 15.8.2 复制未知类型 507 15.8.3 句柄的使用 508 15.9 再谈文本查询示例 511 15.9.1 面向对象的解决方案 513 15.9.2 值型句柄 514 15.9.3 Query_base类 515 15.9.4 Query句柄类 516 15.9.5 派生类 518 15.9.6 eval函数 520 小结 522 术语 523 第16章 模板与泛型编程 525 16.1 模板定义 526 16.1.1 定义函数模板 526 16.1.2 定义类模板 528 16.1.3 模板形参 529 16.1.4 模板类型形参 531 16.1.5 类型模板形参 533 16.1.6 编写泛型程序 534 16.2 实例化 535 16.2.1 模板实参推断 537 16.2.2 函数模板的显式实参 540 16.3 模板编译模型 542 16.4 类模板成员 545 16.4.1 类模板成员函数 548 16.4.2 类型形参的模板实参 551 16.4.3 类模板中的友元声明 552 16.4.4 Queue和QueueItem的友元 声明 554 16.4.5 成员模板 556 16.4.6 完整的Queue类 558 16.4.7 类模板的static成员 559 16.5 一个泛型句柄类 560 16.5.1 定义句柄类 561 16.5.2 使用句柄 562 16.6 模板特化 564 16.6.1 函数模板的特化 565 16.6.2 类模板的特化 567 16.6.3 特化成员而不特化类 569 16.6.4 类模板的部分特化 570 16.7 重载与函数模板 570 小结 573 术语 574 第五部分 高级主题 第17章 用于大型程序的工具 579 17.1 异常处理 580 17.1.1 抛出类类型的异常 581 17.1.2 栈展开 582 17.1.3 捕获异常 583 17.1.4 重新抛出 585 17.1.5 捕获所有异常的处理代码 586 17.1.6 函数测试块与构造函数 586 17.1.7 异常类层次 587 17.1.8 自动资源释放 589 17.1.9 auto_ptr类 591 17.1.10 异常说明 595 17.1.11 函数指针的异常说明 598 17.2 命名空间 599 17.2.1 命名空间的定义 599 17.2.2 嵌套命名空间 603 17.2.3 未命名的命名空间 604 17.2.4 命名空间成员的使用 606 17.2.5 类、命名空间和作用域 609 17.2.6 重载与命名空间 612 17.2.7 命名空间与模板 614 17.3 多重继承与虚继承 614 17.3.1 多重继承 615 17.3.2 转换与多个基类 617 17.3.3 多重继承派生类的复制控制 619 17.3.4 多重继承下的类作用域 620 17.3.5 虚继承 622 17.3.6 虚基类的声明 624 17.3.7 特殊的初始化语义 625 小结 628 术语 628 第18章 特殊工具与技术 631 18.1 优化内存分配 632 18.1.1 C++中的内存分配 632 18.1.2 allocator类 633 18.1.3 operator new函数和 operator delete函数 636 18.1.4 定位new表达式 638 18.1.5 显式析构函数的调用 639 18.1.6 类特定的new和delete 639 18.1.7 一个内存分配器基类 641 18.2 运行时类型识别 646 18.2.1 dynamic_cast操作符 647 18.2.2 typeid操作符 649 18.2.3 RTTI的使用 650 18.2.4 type_info类 652 18.3 类成员的指针 653 18.3.1 声明成员指针 653 18.3.2 使用类成员的指针 655 18.4 嵌套类 658 18.4.1 嵌套类的实现 658 18.4.2 嵌套类作用域中的名字查找 661 18.5 联合:节省空间的类 662 18.6 局部类 665 18.7 固有的不可移植的特征 666 18.7.1 位域 666 18.7.2 volatile限定符 668 18.7.3 链接指示:extern "C" 669 小结 672 术语 673 附录 标准库 675 索引 703

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值