c++ primer 5e学习笔记
第1章
1.标准库 类型和函数的集合,每个c++编译器都必须支持。
2.()运算符:调用运算符。跟随在函数名后,起调用函数的作用

第2章
1.p32:char在一些机器上是有符号的,在一些机器上是无符号的;
2.p33:赋给无符号类型一个超出表示范围的值,结果是初始值对可表示数值总数取模的结果
-1赋值给unsigned char = -1/256=255;
3.p36:可分行书写字符串字面值
cout<<“a cute dog”
“a cute cat”<<endl;
4.p36:转义序列“\”对应的是八进制,“\x对应十六进制
5.p38:变量:具名的可供程序操作的存储空间
6.函数体外部的内置类型变量未被初始化,会默认初始化为0。函数体内未初始化的变量,访问时会编译报错。

    int i;cout << "1" << i << "2" << endl;return 0;

编译报错,虽然编译器检测出来了,但是编译器并不是一定就能检测出来,调试也会很困难

ASCLL码0对应空格

7.存疑:extern 的使用p41
8.预处理器:运行于编译过程之前的一段程序,NULL是预处理变量
9.指向指针的引用:int *p;int *&s = p;从右往左离变量名最近的对变量的类型有最直接的影响p52
10.const只在文件内有效,解觉多文件内使用的办法就是在变量定义之前加extern
11.对常量的引用:格式:const int ci = 1024;
const int &r1 = ci;const不可缺,让一个非常量引用指向一个常量是不允许的。
12.const int &i = 42;允许,i为常亮引用,允许常量引用绑定到非常量的对象,字面值甚至一般表达式,int &i = 42;不允许,引用不是对象,只能绑定带具体对象。p55
13.类型别名,

typedef char *pstring;
const pstring cstr = 0;
//pstring 是char*的别名,cstr是一个指向char的常量指针。
const char *cstr2 = 0;
//cstr2是一个指向const char的指针。

[cstr是一个常量指针,不可改变指针的值,cstr2是一个指向常量的指针,指向的对象是一个常量](https://img-blog.csdnimg.cn/20210215141409206.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80 MjExOTMyNA==,size_16,color_FFFFFF,t_70)
14.auto类型说明符:编译器判断表达式所属类型
15.decltype类型指示符:得到操作数的类型但不计算其结果,返回的结果包含顶层const和引用。decltype(f()) sum = x。如果表达式的内容是解引用,得到的类型是引用而不是引用的对象。decltype(*p)结果类型是int&,而不是int。
decltype((var))双层括号得到的一定是引用。p63
16.预处理器:确保头文件多次包含仍能安全工作。预处理器是在编译之前处理的一段程序#include;
头文件保护符:#define #ifdef #endif,头文件保护符必须唯一

第三章
17.命名空间的using声明:using std::cin
标准库类型string
18.string 读写:string 的cin操作会忽视空格,保留空格可用getline(cin,line);
19.c++中字符串字面值并不是标准库类型string的对象。
20.处理string对象中的字符,在cctype头文件中。c++标准库兼容c语言标准库,C语言中文件名name.h,改成cname,cname中定义的名字从属于std,但name.h则不是。
21.访问string中每个对象:string s = “hello world” ;for(auto c:s)
22.使用超出范围的下标将引发不可预知的结果。慎用下标访问方式,使用前要判空。
标准库类型vector
23.vector:#include
using std::vector;
vector是一个类模板
24.向vector中添加元素:循环体内部包含向vector添加元素,不能用for循环,原因后面说。p91。p169范围for语句不是传统for语句。
25.不能用下标形式向vector添加元素,只能push_back,因为
vector ivex 是一个空vector,不包含任何元素。也就是,只能对确知已存在的元素执行下标操作。访问不存在下标会产生运行时错误:缓冲区溢出(buffer overflow)
迭代器
26.迭代器的对象是容器(或string)中的元素(或字符)。
27.有迭代器的类型都有begin(),end()的成员,返回的就是迭代器。
28.我们并不知道迭代器的具体类型,使用iterator和const_iterator(常量指针)来表示迭代器的类型。p97
29.谨记,但凡使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。
数组
30.不允许拷贝和赋值
31.数组从内向外阅读
int *ptrs[10];//含有10个整形指针的数组;
int (*parray) [10] = &arr;//parray指向一个含有10个整数的数组。
int(&parray)[10] = &arr;//paray引用一个含有10个整数的数组。
32.c++11为数组引入begin()和end(),begin(arr);
33.内置的下标运算符所用的索引值不是无符号类型,这一点与string 和vector不同。
C风格字符串
34.虽然cpp支持,但最好不要使用。
35.c风格字符串与string混用,允许c风格字符串来初始化string,允许加法运算中使用一个c风格字符串。
用string初始化c风格字符串用const char *str = s.c_str();
多维数组
36.用类型别名可简化多维数组的指针:
using int_array = int[4];
typedef int int_array[4];//注意这个写法
typedef int[4] int_array;//错误写法

第四章 表达式
1.运算符:函数调用也是一种特殊的运算符,对运算对象的数量没有限制。
2.重载运算符
3.注意关键字decltype,采用左值右值是不同的。
4.求值顺序:int i = f1() * f2(); *没有规定左右运算的先后顺序。再如cout<<++i<<endl; 结果不一定,可能先求++,也可能先求<<,有四种明确了先后顺序的:&&,||,?:,,(逗号运算符)
5.赋值运算符:使用列表初始化不允许损失精度。p129,赋值运算符优先级低于关系运算符。
6.后置递增运算符优先级高于解引用运算符。
7.位运算符:~,<<,>>,&,^(位异或),|,右移运算符的的左端是否保留符号位要视机器而定。
8.sizeof运算符返回所占的字节数,
sizeof(type);
sizeof expr;//返回的是表达式结果类型的大小,并不计算运算对象的值。sizeof运算不会把数组换成指针来处理。
9.有符号数和无符号数相加:
无符号类型不小于带符号类型,则带符号类型会转换为无符号类型后相加,当带符号类型为负数,会计算出错:
计算出错例子
也可能计算正确,当负数的绝对值小于正数的绝对值时,计算是正确的。
10.强制类型转换(cast):
static_cast<>(exp);//具有明确定义的类型转换,只要不包含底层const,都可使用;
const_cast<>(exp);//改变运算对象的底层const,并且也只能用于改变常量属性,不能用于改变表达式的类型。
reinterpret_cast<>(exp);//避免使用
dynamic_cast 后面p730介绍
应避免使用强制类型转换,
旧式强制类型转换:
type(expr);//函数形式的类型转换
(type)expr;//c语言风格
执行的过程与新式差不多,但形式上不够明确。

第五章语句
1.注意空语句也并非都是无害的;
2.switch语句,case标签必须是整形常量表达式,没有break的情况下,匹配case后面的语句都会被执行,不管后面的case有没有匹配上。
当逻辑不需要break,而是希望逐个判断case时,可把case写在同一行p161
swich语句是一个作用域,case语句并没有区分出不同作用域,需要时加花括号分出作用域。p163
3.传统for语句:语句头的初始条件可以定义多个对象,以逗号间隔,但是多个对象必须是同一类型。
4.范围for语句:c++11新标准
for(declaration : expression)
statement
expression必须是一个序列,拥有能返回迭代器的begin和end成员。declaration定义一个变量,序列中的元素转换成该变量的类型。例如:vectorv = {0,1,2,3,4};for(auto &r : v){statement}。p169
前面p91提到的,不能通过范围for语句增加vector对象,因为范围for语句的结束条件是隐含的,实际是判断vector的end的。
5.do while语句,循环条件是不能定义在循环内部的,定义在循环内部则会每次循环都重新定义。循环条件也不能定义在while条件部分,因为要先执行do再判断条件。
6.跳转语句
break语句:只能终止离它最近的while,do while,for,或switch。
continue语句:终止最近的循环中的当前迭代,开始下一次迭代。
goto语句:无条件跳转到函数内的另一条语句。不要使用goto语句。
7.try语句块和异常处理:
典型的异常包括失去数据库连接以及遇到意外输入。
throw表达式:throw runtime_error(“data must …”);//runtime_error是标准库异常类型的一种,定义在stdexcept头文件中。
try
{program_statements;
throw runtime_error}
catch (runtime_error)
{
//处理代码
}
当异常抛出时,首先搜索抛出该异常的函数,没有找到匹配的catch时,终止该函数,并在调用该函数的函数中找匹配的catch,以此类推。如果最终也没有找到匹配的catch子句,程序转到名为terminate的标准库函数,该函数与系统有关,一般导致程序非正常退出。
标准异常p176:
exception头文件定义了最通用的异常类exception。它只报告异常的发生,不提供任何额外信息。
stdexcept头文件
new头文件定义bad_alloc异常类型p407
type_info头文件定义bad_cast异常类型p731
exception、bad_alloc、bad_cast对象不能为这些对象提供初始值,只能默认初始化。其他类型的异常恰好相反,使用string或c风格字符串初始化这些对象,不允许使用默认初始化。
异常类型只提供一个what的成员函数,返回指向c风格字符串的const char*。提供一些提示文本。

第六章 函数
1.调用运算符:就是函数的圆括号。
函数调用其实是两步:用实参初始化形参,控制权转移给被调函数。
为了与c语言兼容,可以使用关键字void表示函数没有形参:
void f2(void){};
2.局部对象:在cpp中,名字有作用域,对象有生命周期。
3.局部静态对象:有些时候,令局部变量的生命周期贯穿函数调用及之后的时间,可将变量定义为static类型。
局部静态对象在程序执行路径第一次经过对象定义语句时初始化,知道程序终止才被销毁。
4.函数说明:
函数的三要素(返回类型,函数名,形参类型),描述了函数的接口。函数声明也称作函数原型。
建议在头文件中声明,在源文件中定义,函数和变量都应该如此。
5.分离式编译:
编译和链接多个源文件:分离式编译每个文件,通常产生一个后缀名是.obj(Windows)或.o(Unix)文件,后缀名的含义是该文件包含对象代码。
6.参数传递:当形参是引用类型时,我们说他对应的实参被引用传递,或者所函数被传引用调用。当实参的值拷贝给形参时,说实参被值传递,或者说函数被传值调用。
7.指针形参:
8.传引用参数,拷贝导致低效,使用引用避免拷贝。使用引用形参,如果函数无需改变形参值,形参最好声明为常量引用,声明为普通引用是一种错误,会给函数调用者一种误导。
9.const形参和实参:当用实参初始化形参时会忽略顶层const,需要主要:同名函数形参列表应该有区别,忽略了顶层const,
void f(const int i){};
void f(int i){};//两个是一样的效果,不能视为同名函数。
可以用非常量初始化一个底层const,反过来不行。
调用普通(非const)引用形参的函数,不能使用字面值,求值表达式,需要转换的对象,或const类型的对象。
函数定义:f(string &s,char c)
函数调用:f(“hello world”, ‘o’);//错误,不能传入字面值常量p192
更难觉察的情况:
bool f(&s);//f为普通引用形参
bool isf(const string &s)
{
return f(s);//错误,isf中s为常量引用,f普通引用形参,错误。
}
解决思路:不能试图修改isf的形参,这样只是将错误转移到了上一层,应该修改f的形参为常量引用,如果不想改,可以在isf中重新定义一个变量,拷贝s的值。
10.数组形参:不允许拷贝数组,因此不允许以值传递的方式使用数组参数。数组会被转换为指针,因此传递数组时传递的是首元素的指针。
传递多维数组:除了首地址外,还需要除第一维的维度。
void print((*matrix)[10]);
void print(int matrix[][10]);//跟上面的等效
注意:
int *matrix[10];//10个指针构成的数组
int (*matrix)[10],//指针指向10个整数的数组。
11.含有可变形参的函数p197:编写能处理不同实参的函数,如果实参类型相同,可以传递一个名为initializer_list的标准库类型。如果类型不同,可编写可变参数模板
initializer_list:是一种标准库类型,用于表示某种特定类型的值的数组。定义在同名头文件中。
initializer_listls
省略符形参:C语言C标准库varargs中的内容,
void foo(parm_list, …);
12.void类型的函数也可以return expression,但是expr必须是另一个返回void的函数。
13.函数也可以返回引用p201,string &shorterString(string &s1, string &s2),调用函数和返回结果都不会拷贝对象,形参也只能是引用类型。函数返回类型是引用类型时,不能返回函数内部定义的局部变量,因为局部变量在函数结束时所占的内存空间也被释放掉了,局部变量的引用或指针指向不再有效的内存区域。
调用一个一个返回引用的函数得到左值。
14.Cpp11标准规定,函数可以返回花括号包围的值的列表,返回类型是vector
15.允许main函数没有return语句直接结束,编译器会隐式地插入return语句。为了使main函数返回值与机器无关,cstdlib头文件定义了两个预处理变量,EXIT_FAILURE,EXIT_SUCCESS,属于预处理变量。
16.返回数组指针p205:因为数组不能被拷贝,所以函数不能返回数组,函数可以返回数组的指针或引用。但是定义一个返回数组指针或引用的函数比较烦琐,可以使用类型别名:
typedef int arrT[10];//或下面
using arrT = int[10];//或上面
arrt *func(int i)
不使用类型别名的函数的声明:
int(func(int i))[10];//int i是函数形参
cpp1标准可以使用尾置返回类型,auto func(int i) -> int (
)[10];
或者用decltype
17.函数重载:
同一作用域内几个函数名字相同但形参不同称为重载函数,参数的类型和数量都可能不同。main函数不能重载。
不允许两个函数只是返回类型不同。
重载和const形参:顶层const不影响函数传入的对象,拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。
底层const是可区分的。
const_cast和重载:
定义两个同名函数,参数分别为带const和不带const
18.调用重载的函数:二义性调用,有多个函数可以匹配,但是没有最佳选择,这是发生错误。
19.重载与作用域:
一旦在当前作用域中找到所需的名字,编译器就会忽略掉外层作用域中的同名实体,这里是直接忽略,而不是优先级更低。
cpp中,名字查找优先于类型检查。
20.特殊用途语言特性p211:默认实参,内联函数,constexpr函数
默认实参:string screen(int ht = 24, int wid = 81,char background = ‘’ );
默认实参作为形参的初始值出现在形参列表中,可以为一个或多个形参定义默认值,但是一旦某个形参被赋予默认值,它后面的所有形参都要有默认值。想要使用默认实参,只要在调用函数时省略实参就可,默认实参从右往左填补空缺,调用函数时实参从左往右调用参数。
在给定的作用域中,一个形参只能被赋予一次默认实参。通常应该在函数声明中指定默认实参,并将声明放在头文件中。
局部变量不能作为默认实参,
21.内联函数
内联函数可避免函数调用的开销:编译时在函数调用的地方内联地展开。关键字inline,只是向编译器发出一个请求,编译器可以忽略这个请求。
22.constexpr函数:能用于常量表达式的函数,函数体中有且只有一条return语句,为了能在编译过程中随时展开,constexpr函数被隐式地指定为内联函数,给constexpr函数传入一个常量表达式时,返回类型也是常量表达式,用一个非常量表达式调用,则返回一个非常量表达式。
内联函数和constexpr函数放在头文件中,和其他函数不同,可以多次定义,但是多个定义必须完全一致。
23.调试帮助:
头文件保护技术,一些代码只用于调试,正式代码屏蔽。:
assert预处理宏:assert(expr);//如果expr为假,输出信息并终止程序的执行,否则什么也不做。定义在cassert头文件中,预处理名字由预处理器而非编译器管理,可直接使用预处理器名字而无需using说明。
NDEBUG预处理变量:
assert的行为依赖于一个名为NDEBUG的预处理器变量的状态,如果定义了NDEBUG,则assert什么也不做。
#define NDEBUG
命令行选项:CC -D NDEBUG main.c
除了用于assert,还可以用于自己的条件调试代码:
#ifndef NDEBUG

#endif
预处理器定义了几个对于程序调试很有用的名字:
__func__输出当前调试的函数的名字
__FILE__存放文件名的字符串字面值
__TIME__存放文件编译时间的字符串字面值
__DATE__存放文件编译日期的字符串字面值

24.函数匹配p217:当几个函数形参数量相等以及某些形参的类型可以转化的时候,不太容易确定调用哪个重载函数:先找可行的,接下来看参数数量和类型,如果没有最佳匹配,编译器报错。
调用重载函数时尽量避免强制类型转换,如果一定需要,说明我们的形参集合不合理。
25.实参类型转换:
26.函数指针:bool pf(const string&, const string &)
在指向不同函数类型的指针间不存在转换规则。
不能定义函数形式的形参,函数类型的形参会被隐式转换为指向函数的指针,可以直接把函数当作实参用,此时是自动转换为指针。
返回指向函数的指针:
using pf= int(
)(int , int);
pf f1(int);
或者直接声明:
int(
f1(int))(int, int);
或者尾置返回类型:
auto f1(int) ->int ()(int *, int);

第七章 类
类的基本思想是数据抽象和封装,数据抽象是一种依赖于接口和实现分离的编程技术。封装实现类的接口和实现分离。
1.定义成员函数:所有成员都必须在类的内部声明,可以在类外定义,
2.this指针:成员函数通过一个名为this的额外的隐式参数来访问调用他的对象的成员。当我们调用一个成员函数时,用请求该函数的对象地址初始化this,this的目的总是指向“这个”对象,this是一个常量指针,不允许改变this中保存的地址。
3.引入const成员函数,
string isbn() const{return bookNo}
const的作用是修改this指针的类型,this指针是一个常量指针,他所指的这个对象本身也是一个常量,因此this应该既是顶层const,也是底层const,但是没有地方可以把this设置成一个底层const,因此就把const放在成员函数后面。这样的成员函数叫做常量成员函数。这样,因为this是指向常量的指针,因此不能用this改变这个对象,也不能改变这个对象的数据成员。到成员函数就是:常量成员函数不能改变对象的数据成员。
常量对象以及常量对象的引用或指针都只能调用常量成员函数。
4.类作用域及成员函数:编译器分两步处理类:首先编译成员的声明,才轮到成员函数体,因此成员函数体可以随意使用类中的其他成员。
可在类的外部定义成员函数,但类内的声明必须完全一致,用类名加作用域运算符再加函数的格式。
函数可返回this对象:return this;//解引用this指针以获得这个对象。
5.定义类相关的非成员函数:
IO类属于被拷贝的类型,只能通过引用来传递。
6.构造函数:类通过特殊的成员函数构造函数来控制其对象的初始化过程。
构造函数不能声明成const类型,类的const对象在构造函数完成初始化后,才取得常量属性。
没有构造函数时类通过默认构造函数执行默认初始化。是由编译器创建的合成的默认构造函数,如果定义在块内的内置类型或复合类型的对象(数组,指针)被默认初始化,他们的值将是未定义的。因此需要类内赋值或手动构造函数。
在Cpp11中可以sales_data() = default;来要求编译器生成构造函数,跟合成构造函数一样的功能。
构造函数初始值列表:
sales_data(const string &s, unsigned n,double p):bookNo(s), units_sold(n), revenue(pn) {}
冒号和花括号之间的部分称为构造函数初始化列表,负责为新创建的对象的一个或几个数据成员赋初值。
在类的外部定义构造函数。
也可在构造函数的函数体中初始化数据成员。
7.拷贝,赋值和析构
8.访问控制与封装:
访问说明符加强类的封装性:
public说明符之后的成员在整个程序内可被访问,作为接口的部分,构造函数和部分成员函数跟在其后面
private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问。数据成员及作为实现部分的函数跟在其后面。
9.class和struct
struct关键字,定义在第一个访问说明符之前的成员是public,使用class则是private。
10.友元
类可以允许其他类或者函数访问他的非公有成员,方法是令其他类或者函数成为他的友元,在类内增加一条以friend关键字开始的函数声明语句,友元不是类的成员。
尽管当类的定义发生改变时无需更改用户代码,但是使用了该类的源文件必须重新编译。
友员的声明只是指定了访问权限,函数本身需要再次声明。
11.类的其他特性:
在类内定义类型成员:
public: typedef string::size_type pos;
private: pos cursor = 0;
定义类型的成员必须先定义后使用。
令成员作为内联函数:定义在类内部的成员函数是自动内联的,定义在类外部的成员函可以在类内声明时用关键字inline内联。
重载成员函数。
可变数据成员:通过在变量的声明中加入mutable关键字,即使是const成员函数也可以修改可变数据成员的值。
12.返回this的成员函数:返回引用是左值,返回非引用的话只能通过拷贝。
一个const成员函数如果以引用的形式返回*this,那么他返回类型将是常量引用。
13.类类型
类的声明:可以仅声明类而暂时不定义它,这种声明有时被称为前向声明。但是类只有定义了,编译器才知道存储数据成员需要多大存储空间,这个知识点的意义是:声明过后,类内允许包含指向他自身类型的引用或指针。

14.友元再探p250:
类可以把其他类作为友元:如果一个类指定了友元类,则友元类的成员函数可以访问此类包括非公有成员在内的成员。友元关系不存在传递性。
令其他类的成员函数作为友元:必须指明该成员函数属于哪个类。
重载函数和友元:如果一个类想把一组同名成员函数声明成友元,必须每一个单独声明。
再次强调,声明友元只是影响访问权限,并不是声明。
15.类的作用域。
名字查找与类的作用域:类的定义分两步处理:
首先,编译成员的声明,
直到类全部可见后才编译函数体。
但是,在所有声明中使用的名字,必须在使用前确保可见,如果在类内声明中出现在名字在类内该声明之前没有被声明过,则会到类的作用域之外去找,而不是在之后的声明中去找。
类型名要特殊处理:
一般来说,内层作用域可以重新定义外层作用域中的名字,尽管内层已经使用过,但是在类中,如果成员使用了外层作用域中某个名字,则在内中不能再重新定义该名字。因此,类型名的定义通常出现在类的开始处。
16.构造函数再探
构造函数的初始值有时候必不可少,如果成员是const或者引用,必须初始化,当成员属于类类型且该类没有定义默认构造函数时,也必须初始化。但是上述这些情况不能在构造函数内通过拷贝的形式赋值,所以要用初始值列表为这些成员赋值。
初始值列表前后位置关系不会影响实际的初始化顺序。如果用一个成员初始化另一个成员的情况就需要注意:让初始值列表的顺序跟成员声明的顺序一致。
17.委托构造函数:
Cpp11扩展了构造函数初始值的功能,可以定义委托构造函数,
18.使用默认构造函数:
sales_date obj();//我们想要声明一个默认初始化的对象,但是,这里obj会被认为是函数,正确的方法应该是去掉括号,这样就认为是使用默认构造函数初始化对象。
19.隐式的类类型转换:如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制,有时把这种构造函数称为转换构造函数。(其实定义了一个从参数类型向类类型隐式转换的规则):
string null_book = “9-999-999”
item.combine(null_book);
这里我们用一个string自动创建了一个临时的sales_data对象。新生成的这个对象被传递给combine。但是编译器只允许一步类类型转换,
item.combine(“9-999-9999”);//错误
可以抑制上述转换:将构造函数声明为explicit,explicit关键字只能在类内声明出使用,类外定义处不能加。只能用于一个参数的构造函数,多个参数的构造函数也没必要。用explicit关键字声明的构造函数只以直接初始化的形式使用,不能拷贝初始化。
虽然不能对explicit关键字修饰的构造函数进行隐式转换,但是可以为转换显示地使用:
item.combine(sales_data(null_book));//显示转换后调用

20.聚合类:使得用户可以直接访问其成员。
所有成员都是public,
没有定义任何构造函数
没有类内初始值,
没有基类,也没有virtual函数
struct data{
int ival;
string s;
};
初始化数据成员:
data vall = {0, “anna”};//从后往前给成员赋值

21.字面值常量类:
某些类也是字面值类型,字面值类型的类可能含有constexpr的函数成员,数据成员都是字面值类型的聚合类是字面值常量类,不是聚合类如果满足以下条件,也是字面值常量类:
1.数据成员都是字面值类型
2.类必须至少含有一个constexpr构造函数;
3.如果一个数据成员含有类内初始值,则初始值必须是一个常量表达式,或者成员属于某种类类型,初始值必须使用成员自己的constexpr构造函数
4.类必须使用析构函数的默认定义,该成员负责销毁类的对象。
22.constexpr构造函数:尽管构造函数不能是const的,但是字面值常量类的构造函数可以是constexpr函数。因为构造函数没有返回语句,constexpr又要求可执行语句只有返回语句,因此constexpr构造函数一般是空的。
23.p268类的静态成员:静态成员与类本身相关联,而不是跟类的各个对象想关联。static关键字。还有静态成员函数,不包含this指针,不能声明成const的。当在类的外部定义静态成员时,static只出现在类内部的声明语句。静态成员不属于对象,因此不由构造函数初始化,一般来说,在类的外部定义和初始化没有静态成员。
如果静态成员在类的内部初始化,则提供const整数类型的类内初始值,静态成员也必须是字面值常量类型的constexpr。

第二部分 C++标准库

第八章 IO库
Cpp语言不直接处理输入输出,而是通过定义在标准库中的类型来处理IO。
1.IO类
相关的三个独立头文件:
iostream定义了用于读写流的基本类型
fstream定义了读写命名文件的类型
sstream定义了读写内存string对象的类型。
为了支持宽字符的语言,标准库定义了一组类型和对象来操纵wchar_t类型的数据。wcin,wcout,wcerr,wifstream…
2.IO对象无拷贝或赋值。
3.条件状态p279
4.查询流的状态:IO库定义了一个与机器无关的iostate类型,作为一个位集合来使用:
badbit表示系统级错误
failbit可恢复错误,通常还可以修正
如果到达文件结束为止,failbit和eofbit都会被置位,
goodbit的值为0,表示未发生错误。如果其他三个任一个被置位,则检测流状态的条件会失败。good和fail是确定流的总体状态的正确方法,而eof和bad操作只能表示特定的错误。
5.管理条件状态:
流对象的rdstate成员返回一个iostate值,clear()不接受参数版本复位所有错误标志位,clear()接受参数版本置位单一的条件状态位,
6.管理输出缓冲:每个输出流都管理一个缓冲区,用来保存程序读写的数据。
导致缓冲刷新的原因有很多:程序正常结束,缓冲区满,使用操纵符endl,使用操纵符unitbuf,默认情况下,cerr是设置unitbuf的。cin和cerr都关联到cout,因此cin和cerr会导致cout的缓冲区被刷新。

刷新输出缓冲区:endl操纵符换行并刷新缓冲区,IO库中还有两个类似的操纵符。flush刷新缓冲区但不输出任何额外的字符;ends向缓冲区插入一个空字符,然后刷新缓冲区。
unitbuf操纵符:它告诉流在接下来的每次写操作之后都进行一次flush操作。nounitbuf操作符重置流,
cout<<unitbuf;//立即刷新
cout<<nounitbuf;//回到正常的缓冲方式。
注意:程序崩溃,输出缓冲区不会被刷新。

关联输入和输出流:当一个输入流跟一个输出流关联,任何试图从输入流读取数据的操作都会先刷新关联的输出流。
tie不带参数版本,返回指向输出流的指针。如果本对象当前关联到一个输出流,则返回就是指向这个流的指针,如果未关联流,则返回空指针。tie有参数版本接收一个指向ostream的指针,将自己关联到此ostream。x.tie(&o);//j将x关联到o。
每个流最多关联到一个流,但多个流可以同时关联到一个ostream。解开关联的流,给tie传递一个空指针。

7.文件输入输出
ifstream类型从一个文件读取数据,ofstream向一个给定文件写入数据,fstream可以读写给定文件。
fstream继承自iostream,fstream特有的操作p283:
在新Cpp标准中,文件名既可以是string对象,也可以是C风格字符数组,旧版本标准库只允许C风格字符数组。
因为继承关系,可用fstream代替iostream.
当一个fstream对象离开其作用域时,fstream对象被销毁,与之关联的文件会自动关闭。
8.文件模式:
每个流都有一个关联的文件模式,用来指出如何使用文件p286。
in 以读方式打开
out以写方式打开
app每次写操作前均定位到文件末尾
ate打开文件后立即定位到1文件末尾
trunc截断文件
binary以二进制方式进行IO
与ifstream关联的文件默认以in模式打开,与ofstream关联的文件默认以out打开,与fstream关联的文件默认以in和out模式打开。
以默认out模式打开文件会丢弃已有数据,可指定app模式:
ofstream app(“file11”, ofstream::app);

9.string流:
sstream头文件定义了三个类型来支持内存IO,这些类型可以向string写入数据,从string读取数据,就像string是个IO流一样。
istringstream 从string读取数据,ostringstream向string写入数据,stringstream既可以读也可以写。也是继承自iostream

第九章 顺序容器
1.顺序容器概述:
顺序容器类型:
vector 可变大小数组
deque 双端队列
list 双向链表
forward_list 单项链表
array固定大小数组
string
forward_list和array是新Cpp标准增加的类型,与内置数组相比,array是一种更安全更容易使用的数组类型。array对象的大小是固定的,不允许添加删除,不允许改变大小;forward_list没有size操作。
2.容器库概览
每个容器都定义在一个头文件中,头文件与容器同名。容器均定义为模板类,还需要额外提供元素类型的信息。
vector<vector >;//较旧的编译器可能还需要在两个尖括号之间加一个空格。
有些类没有默认构造函数,当我们定义一个保存该类的容器时,需要提供元素初始化器:vector v1(10, inti);
容器操作p295:
3.迭代器:
迭代器范围:
4.类型别名:
iterator容器类型的迭代器类型
const_iterator不能修改元素的迭代器类型
size_type无符号整数类型,足够保存此种容器类型最大可能容器的大小
difference_type带符号整数类型,两个迭代器之间的距离
value_type元素类型
reference元素的左值类型,同value_type&含义相同
const_reference//const value_type&
5.begin和end成员
begin和end有多个版本,带r为反向迭代器,带c为const迭代器。
对const对象调用这些函数时才得到const_iterator.
以c开头的版本是新标准引入,用以支持auto.
6.容器定义和初始化,创建一个容器为另一个容器的拷贝,需要两个容器类型及元素类型相同,但是,用传递迭代器参数拷贝一个范围时,不需要容器类型相同,而且元素类型不相同只要能转换也可以。
顺序容器接收容器大小和元素值来构造:
vector ivec(10,-1);//
标准库array除了制定类型还要指定大小,大小是array类型的一部分。不能对数组类型进行拷贝对象赋值操作,但是array可以:
int digs[10]={0,1,2,3,4,5,6,7,8,9};
int cpy[10]=digs;//错误
7.赋值和swap
array不支持assign(),assign()用于元素拷贝(仅顺序容器)。
list.assign(vector.begin(),vector.end());//
assign()第二个版本:
string.assign(10,“hello”);//接收一个整形值和元素值。
swap并没有交换元素,而是交换两个容器中的数据结构,因此保证在常数时间内完成。
与其他容器不同,对一个string调用swap会导致迭代器引用和指针失效。
与其他容器不同,array调用swap是交换里面的元素。
8.顺序容器操作:
向一个vector,string或deque插入元素会导致所有指向容器的迭代器,指针和引用失效。
insert函数可以接受更多的参数,其中一个版本可接受元素数目和值。insert()返回第一个参数(旧版本标准库中可能会返回void)。
emplace:
emplace_front,emplace,emplace_back,对应push_front,insert,push_back。emplace函数在容器中直接构造元素,因此传递给emplace的参数必须与元素类型的构造函数相匹配,会在容器管理的内存空间中直接创建对象,但是push_back则是创建一个局部临时变量并压入容器中。
9.访问元素:每个顺序容器都有一个front()成员函数,除forward_list外都有back()成员函数,返回的是引用,访问元素的成员函数,返回的都是引用,
下标操作必须保证在范围内,这是程序员的责任。
10.删除元素:
forward_list不支持pop_back,string和vector不支持pop_front,这些操作返回的是void,因此如果需要,要提前保存。erase()返回的是删除元素之后的迭代器,erase(elem1,elem2),删除从elem1开始的后面的元素,也就是结果elem1=elem2,

11.特殊的forward_list操作:
forward_list没有定义insert,emplace,erase,而是定义insert_after(),emplace_after(),erase_after(),还定义了一个before_begin的首前迭代器。
12.改变容器的大小:resize()可增大或缩小容器,但是array不支持resize(),当前大小大于或小于要求大小,array后部的元素会被删除或添加,
在删除或添加的循环中,不要保存end返回的迭代器,应该在每次应该在循环程序中反复调用。
13.vector对象是如何增长大的:
管理容量的成员函数:vector和string的capacity()函数,告诉我们未扩充的当前容器可以容纳多少个元素,reserve(n)分配至少能容纳n个元素的内存空间,shrink_to_fit()将容量减少到size()相同大小。resize()只是改变元素数量而不改变容器容量,
14.额外的string操作p320:
当我们从一个const char*创建string时,指针指向的数组必须以空字符结尾,拷贝遇到空字符时结束,如果还传递给构造函数一个计数值,则不必以空字符结尾。
substr():
可以将以空字符结尾的c风格字符数组insert或assign给一个string,
append()在string末尾插入,replace()是erase()和insert()的一种简写形式,
15.string搜索操作p325:
string::size_type是unsigned类型,
find(),find_first_of(),find_first_not_of(),查找失败返回npos,是size_type类型,初始化为-1。
16.compare()函数
17.数值转换p328:从string中提取数值。
18.容器适配器:容器,迭代器,函数都有适配器,
标准库定义了三个容器适配器:stack,queue,priority_queue,一个容器适配器接收一个已有的容器类型,使其行为看起来像一种不同的类型,适配器是一种机制

第十章 泛型算法

1.概述:大多数算法都定义在头文件algorithm中,标准库还在头文件numeric中定义了一组数值泛型算法,
迭代器令算法不依赖容器,算法永远不会执行容器的操作。
2.初始泛型算法:
一些算法,例如equal,接收三个迭代器,前两个表示第一个序列的范围,第三个表示第二个序列中的首元素,这时,是假定第二个序列至少跟第一个序列一样长,确保算法不会访问第二个序列不存在的元素是程序员的责任。
向目的位置迭代器写入数据的算法是假定容器的位置够大,要能容纳写入的元素,泛型算法不直接操作容器,因此也不能为容器扩容。
插入迭代器:insert_iterator,
3.定制操作p344:
谓词:接受谓词参数的算法对输入序列中的元素调用谓词,谓词参数可以是一个或两个,称为一元谓词,二元谓词。
lambda表达式:结构与函数类型,但是lambda可以定义在函数内部:
[捕获列表](参数)->返回类型 {函数体};
auto f=[]{retrn 42;};
lambda必须使用尾置返回来指定返回类型,如果没有指定类型,可从表达式推断。如果无法推断,返回void类型。lambda不能有默认参数
auto wc = find_if(words.begin(),words.end(), [sz](const string &a){return a.size()>=sz;}

c++primer学习笔记相关推荐

  1. C++ Primer 学习笔记(第四章:表达式)

    2019独角兽企业重金招聘Python工程师标准>>> ##C++ Primer 学习笔记(第四章:表达式) [TOC] ###4.1 基础 左值和右值: 当一个对象被用作右值的时候 ...

  2. 【C++ Primer 学习笔记】: 容器和算法之【泛型算法】

    本系列博客主要是在学习 C++ Primer 时的一些总结和笔记. [C++ Primer 学习笔记]: 容器和算法之[泛型算法] 本文地址:http://blog.csdn.net/shanglia ...

  3. C++ Primer 学习笔记 第十章 泛型算法

    C++ Primer 学习笔记 第十章 泛型算法 336 find函数 #include <iostream> #include <vector> #include <s ...

  4. C++ Primer 学习笔记 第一,二章

    2021年4月4日,我终于开始学习C++啦,下面的笔记会记录着我的心酸的学习历程,每个标题会记录着下面代码在<C++中文版 Primer>中的页码 P6 实现两数之和 # include ...

  5. C++Primer学习笔记:第1章 开始

    本博客为阅读<C++ Primer>(第5版)的读书笔记 ps:刚开始的时候我将所有的笔记都放在一篇博客中,等看到第六章的时候发现实在是太多了,导致我自己都不想看,为了日后回顾(不那么有心 ...

  6. C++ Primer学习笔记(一)

    始终对C++念念不忘,看过 一个32岁入门的70后程序员给我的启示  之后,心情激荡,更是一发不可收拾. 认真地说,我不是一个执着的人,见异思迁,好读书而不求甚解,兼之情绪化(~~ 某些方面),于是怒 ...

  7. C++Primer学习笔记:第6章 函数

    通过调用运算符()调用函数 函数的调用完成两项工作: 用实参初始化函数对应的形参 将控制权转移给被调用函数:主调函数的执行被暂时中断,被调函数开始执行 尽管实参与形参存在对应关系,但是并没有规定实参的 ...

  8. C++Primer学习笔记(二)

    17.string对象中字符的处理: cctype头文件中定义: isalnum(c) 如果c是字母或数字,则为true isalpha(c) 如果c是字符,则为true iscntrl(c) 如果c ...

  9. 【C++ Primer学习笔记】第1章:快速入门

    本章介绍C++的大部分基础要素 1.1编写简单的C++程序 操作系统通过调用main函数来执行程序,main函数再来调用其它函数,main函数返回值为状态指示器. 1.2初窥输入\输出 C++并没有直 ...

最新文章

  1. c语言实现数码管显示qq号,各位大神,如何用C语言实现在数码管上实现1234同时亮...
  2. 对DIP IoC DI的理解与运用
  3. linux配置ssh免密码,Linux下配置SSH免密通信 - “ssh-keygen”的基本用法
  4. 边缘检测的各种微分算子比较(Sobel,Robert,Prewitt,Laplacian,Canny)
  5. 谨以此片,献给你身边的产品经理
  6. 2017年09月23日普级组 数列
  7. Linux网络技术管理
  8. C++用递归方式实现在对不更改随机数组的情况下查找最大值
  9. 腾讯上海某实验室SQL面试题——查询最后任职信息
  10. 解决 Microsoft Excel has stopped working
  11. python中str是什么_python的str()字符串类型的方法详解
  12. 突然讨厌做前端,讨厌代码_你讨厌正则表达式吗? 那么,我为您提供解决方案......
  13. SpringCloud Gateway 服务网关,过滤器
  14. mt4 指标 涨跌幅 颜色k线_精品主图 精准K线买卖点提示通达信指标公式源码
  15. PCL:RANSAC 空间直线拟合
  16. jq/js获取屏幕宽度和高度
  17. 浅谈文字编码和Unicode(中)[转]
  18. 二叉搜索树,就这,就这啊。
  19. Codeforces 1006A
  20. Day16_IO框架1(File类, IO流, 字节流字符流, IO异常, Properties)

热门文章

  1. 阿里云Ubuton开MCJava服务器_每小时不到1元,弹性计算服务按流量缴费
  2. 个人项目——二柱子的生成小学生四则运算题程序
  3. windows下kafka环境完整搭建,Python调用kafka构建完整实例分析与应用
  4. 从春招到秋招,一个本科生的求职之路
  5. 记一次android任务栈页面跳转问题
  6. postgresql 在流复制模式下,WAL发生以下错误的对处方法
  7. stm32f4xx-外部中断
  8. b站pink老师JavaScript的PC端网页特效 案例代码——仿京东放大镜效果
  9. 2020上海全国计算机一级考试时间,2020全国等级计算机考试时间(全国计算机一级报名时间)...
  10. 基于Java毕业设计疫情下的居民管理系统源码+系统+mysql+lw文档+部署软件