C++笔记
将数字以十六进制输出:cout<<hex<<100<<endl;
将数字以八进制输出:cout<<oct<<100<<endl;
精度控制
include
保存a位小数:setprecision(a)
将b保留a位:cout<<setprecision(a)<<b<<endl
将b保留小数点后a位:cout<<setiosflags(ios::fixed)<<setprecision(a)<<b
const限定符:限制局部变量为常量
ae+N:a*10n
ae-N:a*10-n
名称空间:控制名称作用域
程序中创建不同名称空间
- 声明区域:可以在区域中进行声明
- 潜在作用域:从变量声明点开始,到声明区域
使用空间名名称
-
除了用户定义的名称空间,还有全局文件名称空间
-
名称空间可嵌套使用,开放且可以随时添加新内容<如果同名做合并操作>
-
名称空间可以匿名隐式加上static
-
可以起别名:A=B
-
匿名的名称空间可直接访问
构造函数:程序声明对象是否可自动调用
-
数据成员名中使用m_前缀或成员名中使用后缀_
-
public:一个类的构造函数名和类名相同
-
引用:&别名=原名 两个名称共享内存空间
-
引用一旦初始化就无法更改,引用作函数传参:形参修饰实参
-
简化实参:值、地址、引用
-
本质是常量指针const
-
如果函数声明有默认实参,那么函数定义则不用加(一个就行)
-
现阶段函数占位意义不大
函数重载细节
- 引用作为条件
- 碰到默认参数(报错)
类中属性、行为统一叫成员
成员属性、成员变量、成员方法
权限 | 类内 | 类外 | 继承性 |
---|---|---|---|
public(公共权限) | 可访问 | 可访问 | 可继承 |
protected(保护权限) | 可访问 | 不可访问 | 可继承 |
private(私有权限) | 可访问 | 不可访问 | 不可继承 |
类外想要访问私有/保护权限对象,只能通过公共权限提供接口
class默认权限私有
struct默认权限公共
初始化列表方式
-
fun(int a,int b):A(a),B(b)
-
类对象作为类成员
-
隐式转换法
-
类内static:共享内存
静态成员对象两种访问方式
-
通过对象访问 对象.成员
-
通过类名访问 类名::成员
-
静态成员变量有访问权限
-
直接在类里面定义的变量为私有变量
构造函数:类名(){}
无返回值且无void
与类名相同
可以有参数且发生重载
- 调用对象时自动调用构造
析构函数:~类名(){}
- 创建类时调用构造函数,类注销时调用析构函数
- 拷贝构造函数,默认构造调用不用加括号
- 浅拷贝:拷贝指针
- 深拷贝:拷贝数据
- 静态成员函数(有访问权限的),所有对象共享同一个函数(内存空间),只能访问静态成员变量
- 不可以访问非静态成员变量
对象模型和this指针:成员变量和成员函数分开存储
-
空对象占用内存空间1B,为了区分空对象位置
-
每个空对象有独一无二地址
-
this指针是隐含每一个非静态城公园函数内的指针
用途:
-
解决名称冲突
-
返回对象自身
-
指向被调用成员函数所属对象
-
this指向p2的指针,*this指向p2本体
常函数:
-
成员函数后加const
-
不可修改成员属性
-
加关键字mutable,常函数依然可修改
-
成员后加congst,修饰this指向
类内声明:friend void fun(c)
-
这样fun可访问c的私有成员,不用特地使用public声明
-
类外创建类内成员函数
-
类名::成员函数(){}
运算符重载
type operator+(type &A){}
-
成员函数重载(可链式嵌套)
-
全局函数重载
type operator+(type &A1,type &A2){}
-
给运算符新的定义,赋予其另一种功能
-
适应不同数据类型
-
对于内置数据类型不可重载
-
不要滥用运算符重载
左移运算符重载<<
-
operator<<()
-
全局函数重载左移运算符(只能在全局中)
-
ostream operator<<(ostream &cout,type &A){}
递增运算符重载++
-
operator++()前置重载
-
operator++(int)后置重载
-
记录结果
-
后递增
-
返回
-
总之,重载一定会用到operator
赋值运算符重载
关系运算符重载
函数调用符重载()
-
仿函数:重载起来像函数被调用
-
继承:下级别成员拥有上级别的共性
减少代码重复
class A:public B{}
- A继承B中所有内容
class 子类:继承方式 父类{}
public、protected、private
-
A:元素+方法(多种)
-
B:元素+方法(单种)
继承中对象模型
-
父类中所有非静态成员都会被子类继承
-
继承构造和析构顺序
-
先构造父类,后子类
-
先析构子类,后父类
-
继承同名成员处理方式
-
通过子类对象访问继承成员,应加作用域 父类::子成员
-
直接调用的是子类成员
-
子类成员会隐藏父类中继承下来的方式
-
同名静态成员继承:对象.类名访问
-
多继承:class子类:方式 父类1,方式 父类2
菱形继承:二义性处理
虚继承(继承指针)
-
多态:静态多态:函数/运算符重载
-
动态多态:派生类和函数运行时多态
满足条件:
继承关系
子类重写父类虚函数
重写:函数返回值类型、函数名、参数列表相同
动态多态使用:子类重写父类虚函数
父类引用接受子类对象可行,允许父子类型转换。而要让父类使用子类的方法,则将父类定义为虚函数就行。
引用时晚绑定则可避免引用时父类指向子类问题。
引用类型取决于等号右边
原理剖析
vfptr:virtual function pointer
- 虚函数指针表
vftable:虚函数表(记录虚函数地址)
-
当子类重写父类虚函数,子类虚函数表内部会替换为子类虚函数地址
-
当父类指针或引用指向子类对象,发生多态
开闭原则:扩展开放,修改关闭
-
计算器基类:抽象
-
高内聚,低耦合
纯虚函数:
-
父类中虚函数无实际意义
-
重点在于子类中重写的功能
-
当类中有了纯虚函数,这个类也称抽象类
-
抽象类无法实例化对象,因此抽象子类必须重写父类,否则无法实例化对象
-
虚函数代码毫无意义,作用在于子类重写
-
用父类指针接收不同的子类
-
而多态给函数提供扩展性(传入指针)
虚析构/纯虚析构
-
父类对象无法析构子类对象,从而导致内存泄漏。虚析构解决此类问题
-
virtual ~fun()=0
-
纯虚析构函数应当有具体实现
-
而调用子类时使用指针
文件操作
-
ofstream:写操作
-
ifstream:读操作
-
fstream:读写
创建流对象:
-
ofstream ofs;
-
ofs.open()
-
ofs<<数据;
-
ofs.close()
打开方式:
-
ios::
-
in读
-
out写
-
ate文件尾
-
app追加
-
trunc删除创建
-
binary二进制
读写步骤相似
-
ifs.getline()行读
-
ifs.get()一个个读
模板
泛型编程
函数模板\类模板
template
声明一个模板,以至于后面不报错
类型不同,其它一样,则可用模板
template
-
自动类型推导,显示指定类型
-
函数模板注意事项
-
自动类型推导,必须推导出一致数据类型T才可使用
-
模板必须确定T数据类型才能使用
typename/类模板
-
显式指定类型发生隐式类型转换
-
普通函数和函数模板调用规则
-
如果函数模板和普通函数都可调,优先使用普通函数
-
可使用空模板参数列表强制使用函数模板
-
函数模板可发生重载
-
如果函数模板可产生更好匹配,优先调用函数模板
-
如果函数模板产生更好匹配,优先调用函数模板
局限性
-
并非万能,特殊数据类型需要特殊自定义数据类型实现具体化代码,优先调用具体化
-
template<>fun(typename &A)
-
故不用运算符重载也能实现
类模板
-
template<class A,class B>
-
无自动类型推导功能,可以有默认参数
-
类模板可以有默认参数
-
类模板对象作函数参数
typeid(A).name()
类模板与继承
子类继承的父类式一个类模板
需要指定父类中T的类型,如果不指定,编译器无法给子类分配内存
如果想灵活指定父类中T类型,子类也需要变类模板
如果父类是类模板,子类需要指定出父类中T的数据类型
类模板成员函数类外实现
template<class T1,class T2>
class P{}
template <class T1,class T2>
P<T1,T2>:😛(T1 A,T2 B){}
成员函数类外实现
类模板分文件编写
将声明和实现包含到一个文件
.hpp
.h声明
.cpp 实现
类模板与友元
类内:直接类内声明友元即可
类外:提前让编译器知道全局函数存在
编程技巧:
创建头文件.h
功能在.h中进行声明
具体实现在cpp中进行
父类指针承接子类对象
STL模板库(standard template libary)
泛型编程->提升代码通用性
建立一套数据结构和算法标准
- 容器
- 序列式:每个元素都有固定位置
- 关联式:没有严格顺序关系
- 算法
- 质变:更改元素内容
- 非质变:不会更改元素内容
- 迭代器
- 算法通过迭代器访问容器
- 输入、输出、双向、前向、随机访问
- 仿函数
- 适配器
- 空间配置器
容器
-
vector 存放自定义数据类型
-
vector
容器可存储地址
- vector
容器中嵌套容器
-
vector
-
二维数组实现方式
string容器
赋值操作
-
string& operator=(const char* s)
- 将char*赋值给当前字符串
-
string& operator=(const string& s)
- 把字符串s赋值给当前字符串
-
string& operator=(char c)
- 把字符串赋给当前字符串
-
string& assign(const char *s)
- 把字符串s赋给当前字符串
-
string& assign(const char* s,int n)
- 把字符串s前几个字符赋给当前字符串
-
string& assign(const string& s)
- 用n个字符c赋给当前字符串
-
string& assign(int n,char c)
- 字符串拼接
-
append(const char* s,int n)
- 将s前n个字符连接到当前字符串结尾
-
append(const string& s,int pos,int n)
- 将s从第pos开始几个字符连到字符串结尾
string查找
-
find(string,pos)
- 查找str第一次出现位置
-
find(s,pos)
- 查找s出现的位置
-
find(char,pos)
- 查找char第一次出现位置
-
refind()
- 从最后开始查找
-
replace()
替换
-
string比较:按ASCII码对比:=返回0
-
compare():<返回-1
[]返回单个字符
at()
string插入和删除
-
insert()
-
erase()
string截取
-
.substr(int a,int b)
-
从第a+1个开始取长度为b
vector可以动态扩展
front() back() push_back()
vector容器
-
vector
v1(v.begin(),v.end()) -
vector
v2(a,b) a个b传入v2 -
vector
v3(v) 拷贝构造函数
赋值
- =
- assign(begin)\assign(end)
- assign(a,b)
容量大小
-
empty() 判断是否为空
-
capacity() 容器容量
-
size() 容器中元素个数
-
resize() 重新指定容器长度,长则填充短则删除
vector删除、插入
-
pushback()
-
pop_back()
-
insert(pos,element)
-
erase(pos)
-
clear()
数据存取
- at().[].front().back()
容器互换
-
swap收缩内存
-
v1和v互换
-
v1.swap(v)
预留空间
- reserve(len)
减少vector动态
- 预留len大小空间,位置不初始化,元素不可访问,避免存储过程中不断开辟新空间
deque容器
双端数组
与vector区别
- vector对头部插入删除效率低,数据量越大,效率越低
- deque相对而言,对头部插入删除比vector快
- vector访问元素速度比deque快
内部有中控器,维护每段缓冲区地址,支持随机访问
-
deque构造和vector相似:赋值\大小\插入\删除\数据与vector相同
-
deque排序
-
sort(d.begin(),d.end())
默认升序
-
对于支持随机访问的迭代器容器
-
都可用sort算法直接排序
stack容器
list容器
- 链表(双向循环链表)
- 结点:数据\指针
- 迭代器只支持前移后移
赋值交换
- assign()
- swap()
大小操作
- size()
- empty()
- resize()
- reverse()
- sort()
set\nultiset容器
- 关联式容器,底层为二叉树
- set容器不允许插入重复值,且自动排序
- multiset允许插入重复值
接口
- size()
- empty()
- swap()
- insert()
- clear()
- erase()
- find()
- count()
pair容器
pair
set排序规则
指定自定义排序规则
仿函数 operator() 函数重载
map\multimap全为pair
字典 key:value
map 不允许重复key值,而multimap允许insert(pair)
map容器
- 函数对象重载()时叫仿函数,本质是类可像普通函数那样调用
- 函数对象可以有自己的状态(成员变量)
谓词
- 返回bool类型仿函数
- 如果operator()接受一个参数,那么叫一元谓词
- 内建函数对象:算数\关系\内建
include
一元仿函数,nagate<>取反
关系仿函数\逻辑仿函数
常用仿函数
常用算法:
常用遍历算法
for_each(v.begin(),v.end(),func())
transform 搬运容器到另一个容器
查找:查找指定元素,返回指定迭代器
- find:查找元素
- find_if:按条件查找元素
- adjacent_find:查找相邻重复元素
- binary_search:二分查找法
- count:统计元素个数
- countif:按条件统计元素个数
常用排序算法
- sort:对容器元素排序
- randomshuffle:打乱元素次序
- merge:容器元素合并
- reverse:反转指定范围元素
拷贝:替换算法
- copy:容器内指定范围元素拷贝到另一容器
- replace:指定范围内调元素改为新元素
- replace_if:指定范围满足条件元素替换为新元素
- 互换两容器元素
算术生成算法
- accumulate:计算容器累计元素总和
- fill:向容器添加元素
集合算法
- set_intersection:求容器交集
- set_union:求并集
- set_difference:求差集