C++知识点回顾
第二章 基本内置类型
类型转换 无符号类型的表达式
无符号数减去一个数要保证不能是负数。
定义在函数体内部的内置类型将不被初始化
声明一个变量而不是定义一个变量可以在变量名前面加上extern。
嵌套的作用域,使用 :: 来显示的说明全局变量。
//显示说明使用全局变量reused
cout<<::reused<<endl;
复合类型
引用:对象的另外一个名字,引用本身不是一个对象,所以不能定义引用的引用。
指针:指向另外一个种类型的符合类型。
void* 指针:可以存放任意对象的地址。
定义多一个变量:
int *p1,p2; //p1是指向int的指针,p2是int
指向指针的引用:(从右向左阅读r的定义)
int i = 4;
int *p;
int *&r = p; //r是一个对指针p的引用
顶层const:表示指针本身是个变量
底层const:指针所指对象是一个变量
类型别名:
typedef double wages; //wages是double的同义词
// 新标准可以使用新的方法,别名声明
using SI = Sales_item; //SI是Sales_item的同义词
decltype类型说明符
可以分析一个表达式,并得到其类型。
例外:
int i = 42,*p = &i, &r = i;
decltype(r+0) b; //b是一个int
decltype(*p) c; //错误,c是一个int&,必须初始化
decltype((i)) d; //错误,d是一个int&,必须初始化
如果表达式的内容是解引用操作,将得到引用类型。
decltype((variable))得到的结果永远是引用。
C++11新规定,可以为数据成员提供类内初始值。
第三章 字符串向量和数组
头文件一般不使用using声明。
getline读取一整行,直到遇到换行符,换行符也被读进来。
字符串字面量和string是不同的类型。
string s1 = "hello";
string s4 = s1 + ", "; //正确
string cc = "23" + "234" + s;; //错误,不能把字面量直接相加
处理string中的字符
isalnum(c) c为数字或者字母时为真
ispunct(c) c为标点符号时为真
isspace(c) c为空白时为为真
tolower(c) 输出c对应小写
toupper(c) 输出c对应大写
迭代器运算:
vector和string的迭代器可以直接接一个数
iter + n
iter - n
数组:
其维度必须是一个常量表达式。
数组不允许拷贝和赋值。
对于复杂的数组声明:
由内向外阅读要比从右向左好。
int *ptrs[10];
int (*Parray)[10] = &arr; //Parray指向一个包含10的整数的数组
指针与下标:
int ia = {2,3,4,5,7};
int *p = &ia[2]; //p指向ia中索引为2的元素
int j = p[1]; //j等于ia中索引为3的元素
int k = p[-2]; //k等于ia中索引为0的元素
第四章 表达式
左值和右值:
当一个对象被用作右值的时候,用的是对象的值;当一个对象被用作左值的时候,用的是对象的身份(内存中的位置)。
命名的强制类型转换:
static_cast, dynamic_cast, const_cast 和 reinterpret_cast
第六章 函数
形参可能的情况下,进行使用常量引用,这样扩大了接收实参的范围。
数组形参
当为函数传递一个数组时,实际上传递的是指向数组首元素的指针。所以函数并不知道传递过来的数组的大小是多少。
因为数组不能被拷贝,所以函数不能返回数组。但是可以返回数组的指针和引用。
函数重载:同一个作用域中,几个函数有相同的名字,但形参列表不同。
调试帮助:
预处理变量
__func__ 存放函数的名字
__FILE__ 存放文件名的字符串字面值
__LINE__ 存放当前行号的整形字面值
__TIME__ 存放文件编译时间的字符串字面值
__DATE__ 存放文件编译日期的字符串字面值
第七章 类
class关键字与struct关键字的区别:唯一区别是默认访问权限不同。
类允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友元。
一个类指定了友元类,那么友元类的成员函数可以访问此类包括非公有成员在内的所有成员。友元关系不存在传递性。
内联函数,最好只在类的外部定义的地方说明inline,可以使得类更容易理解。
使用mutable关键字声明的变量,在const函数内也可以修改某个数据成员。
构造函数成员初始化顺序:按在类中出现顺序初始化。如果成员时const或者引用的话,必须将其初始化。
如果构造函数只接受一个实参,则实际上定义了转换此类类型的隐式类型转换机制。但是可以使用explicit关键字来抑制隐式转换。
指针成员可以是不完全类型,静态成员可以是不完全类型。
第八章 IO库
iostream 处理控制台io
fstream 处理命名文件IO
stringstream完成内存string的IO
第九章 顺序容器
顺序容器包括:
vector 可变大小数组,内存连续
deque 双端队列,内存看上去连续
list 双向链表,内存不连续
forward_list 单向链表
array 固定大小数组
string 与vector相似,专门用来保存字符
forward_list中插入和参数元素与其他顺序容器不同,因为删除的是有元素没有指向其前驱的指针,所以添加删除的时候,必须关注两个迭代器,一个指向要处理的元素,一个指向其前驱。
容器操作可能使迭代器失效:
添加元素:
- 如果容器是vector或者string,且存储空间重新分配,则指向容器的迭代器、指针和引用都会失效。若没有重新分配,插入位置前的迭代器不会失效,但插入位置之后的迭代器、指针和引用都会失效。
- 对于deque插入到收尾位置之后的任何位置都会导致迭代器、指针和引用失效。首位位置添加元素,迭代器会失效,但是指向存在的元素的指针和引用不会失效。
- 对于list和forward_list,指向容器的迭代器、指针和引用任然有效。
删除元素: - list和forward_list指向容器其他位置的迭代器引用和指针任然有效
- 对于deque删除首尾元素,其他迭代器、引用和指针不会失效。删除其他位置的元素,都失效。
- vector和string,删除元素后,位置之后的迭代器、引用和指针都失效,之前的仍然有效。
可以在while循环中,使用end每一次都计算尾后迭代器判断是否到达了最后。
string 的其他操作:可以参考 标准C++string类用法总结
三个顺序容器适配器:stack、queue、priority_queqe
第十章 泛型容器算法
标准库算法对迭代器而不是容器进行操作,因此,不能(直接)添加或删除元素。
lambda表达式
[capture list](parameter list) -> return type { function body }
[=] 隐式捕获列表,采用值捕获方式
[&] 隐式捕获列表,采用引用捕获方式
当doby只有一条return语句时,可以推断出返回类型。
bind函数,可以看成一个通用的函数适配器。
额外的几种迭代器:
插入迭代器
流迭代器
方向迭代器
移动迭代器
对于list和forward_list应该优先使用成员函数版本算法,而不是通用版本算法。
例如:reverse(), remove(),merge(),sort(),unique()
链表特有版本与通用版本间最大的区别是链表版本不会改变底层的容器。
第十一章 关联容器
有序关联容器:(底层使用红黑树实现)
map
set
multimap
multiset
无序集合:(底层使用哈希表实现)
unordered_map
unordered_set
unordered_multimap
unordered_multiset
在multimap或multiset中查找元素可以使用lower_bound和upper_bound
第十二章 动态内存
智能指针:
shared_ptr
unique_ptr(早期的auto_ptr具有unique_ptr的部分特性,但不是全部,不能在容器中保存auto_ptr,也不能从函数返回auto_ptr)
weak_ptr 不控制指向对象生存期的智能指针,无法直接访问对象,要调用lock,返回一个指向共享对象的shared_ptr
unique_ptr直接支持对动态数组的管理,shared_ptr不支持管理动态数组,如果希望使用shared_ptr管理一个动态数组,必须提供自己定义的删除器。shared_ptr未定义下标运算符。而且智能指针不支持指针算数运算。
第十三章 拷贝控制
拷贝构造函数
拷贝赋值函数
移动构造函数
移动赋值函数
析构函数:函数体自身并不直接销毁成员,成员是在析构函数体之后隐含的析构阶段中被销毁的。
使用 =default 可以显示的要求编译器生成合成版本。
使用 =delete 定义删除函数,指出我们希望将它们定义为删除的。
析构函数不能是删除的成员。
如果一个类有数据成员不能默认构造、拷贝、复制或销毁,则对应的成员函数将被定义为删除的。
具有引用成员或默认构造的const成员的类,编译器不会为其合成默认构造函数。有引用成员的类,合成拷贝赋值运算符被定义为删除的。
右值引用,必须绑定到右值的引用,通过&&获得右值引用。
可以将一个const的引用绑定到一个右值上。
变量表达式都是左值。
move标准库函数可以获得绑定到左值上的右值引用。
第十四章 重载运输符与类型转换
有些运算符必须作为成员
- 赋值,下标,调用和成员访问箭头运算符必须是成员
- 符合赋值运算符应该是成员
- 改变对象状态的运算符与给定类型密切相关的算符应该是成员
- 具有对称性的运算符可能转换任意一端的运算对象,通常应该是普通的非成员函数(提高适用性)
区分前置和后置递增递减运算符,用一个int形参来区分。
class str{
public:
str& operator++(); //前置运输符
str& operator--(); //前置运输符
str& operator++(int); //后置运算符
str& operator--(int); //后置运算符
}
定义了调用运算符,该类的对象称作函数对象。
标准库定义的函数对象:
例如
plus<type> greater<Type>
minus<type> less<Type>
标准库function类型
第十五章 面向对象程序设计
继承 封装 多态
c++的多态,通过虚函数机制,实现了多态
使用override说明符,可以防止不小心出错。
函数定义为final后,不允许后续覆盖此函数。
可以使用作用域运算符来回避虚函数机制。
可以使用using声明改变派生类继承的某个名字的访问级别。
名字的查找先于类型检查。
静态类型决定了该对象哪些成员可见。
一条基类成员函数的using声明语句就可以把函数的所有重载实例添加到派生类作用域中。
第十六章 模板与泛型编程
函数模板
类模板
普通类的成员模板
类模板的成员模板
使用尾置返回类型声明返回类型。
引用折叠
可变参数模板
一个特例化版本本质是一个实例,而非函数名的一个重载版本