导图社区 C加加
c++语言对C语言的功能做了一定的扩充,同时增添了面向对象编程机制,引入面向对象编程机制。感兴趣的小伙伴可以下载收藏哦~
编辑于2021-12-24 16:31:10C++基础
简介
程序运行
程序运行
操作系统将指令载入到内存中。每条指令都有特定的内存地址
计算机逐步执行这些指令
有时从一个地址跳到另一个地址
指令执行后存储该指令的内存地址,并将指令参数复制到堆栈。跳到标记函数起点的内存单元调用函数执行函数代码。然后跳回来到指令保存的地址
存指令,存参数;跳到调用函数执行;再跳回指令函数返回结果
内联可以通过牺牲内存减少函数间跳跃
C++两大特点
面向对象
三大特点
封装
继承
子继承父类方法;父继承子类对象
子类呈对象
父类呈方法
多态
同种类,不同的方法
同名的通过命名空间可以区分
三大内容
对象
特定个体
如cout,cin
成员
描述的点
属性
具体的操作
泛型编程
模板是泛型编程的基础
模板指的是通用函数
C++编程
函数的组成
头文件
常量
用const表示
函数原型
类声明
类成员
构造函数
函数声明
附函数文件
函数的定义
函数主文件
命名空间
命名空间的用处
命名空间主要是用于区分不同库的同名函数,类,变量,对象等
相当于为某个函数,类,变量,对象等创建了特定的名字
例子
cout和cin与命名空间与类
std标准命名的对象。该对象属于iostream类的对象,因此可用iostream的方法
std命名空间里调用了iostream类的2.h文件
在std命名空间里,该对象作为输入输出流存在
初始化变量
2个方法
标准法
大括号法
类数组法
输入输出函数
cin/cout属于iostream类,在std中固定了该对象的命名
输入流
cin(很智能)
cin的智能性
类型转换
原本内容
文本数据或二进制数据
内容转换例子(三种)
cin对象负责将文本类型转为其他类型
int/double
不断读取输入流,直到遇到不是对应的为止
char
不用转换
字符串
单词输入
cin>>
完整输入
cin.getline
遇到回车为止,并添加空字符
四种类型的cin输入
普通输入
读取方式
单词读取
字符输入
cin.get()
两种方式
函数参数被修改为自动默认引用型
1个参数
0个参数
字符有效范围
范围只在ASCII内
遇到EOF不会存储
字符串输入(非单词输入)
四种方式
cin>>
单词输入
cin.get()
2个参数
特点
保留回车到下一输入流中
读到换行符结束;添加空字符
用来存储输入行的数组名
输入流保留回车问题
会让下一个getline和get读入回车直接结束输入
解决方法
可通过两个get来消除换行符带来的问题
拼接方式
通过cin.clear恢复输入
cin.getline()
cin.getline()
只针对char数组,不针对string
输入字符串
特点
丢弃换行符
读到换行符结束;添加空字符
用来存储输入行的数组名
拼接法
getline()
可对string类进行输入
丢弃换行符
连续输入
对象变对象
给两个变量赋值
返回与错误检测
输入结尾检测三种方法
eof,fail,bad()
读取到EOF
eof()返回true
读取到类型不匹配(如EOF也会返回true)
fail()返回true
读取文件时文件受损
bad()返回true
good()
没有任何错误时返回true
指出最后一次读取输入的操作是否成功
变量名>>数值
该表达式结果为对象名inFile
在需要bool的情况下,该结果会返回对象名.good
错误返回
智能返回值
while与if中
可自动转为bool
终止输入
false类型停止输入
输入类型与变量类型错误
遇到EOF
如需输入,用类中clear方法
cin.clear()
cin特殊性
char型数组
输入数组名或者指针
结果变成输入内容
输出
cout(很智能)
该对象是输出流
两种输出方法
普通输出
两种特殊输出
多进制
利用插入运算符将随后插入的进制全部转换
cout<<hex
cout转化成16进制输出
cout<<oct
cout转化成8进制输出
浮点型
浮点型默认小数点后6位
字符输出
cout.put
cout使用了类的方法put
输出一个字符
字符串输出
cout<<
cout特殊性
char型数组
输入字符型数组名
结果变成内容
输入char指针指向数组
结果变成内容
输入char型数组地址
用&
运算符
插入运算符<<
抽取运算符>>
数据类型
左值
整型
默认类型
int
限制
位数限制
int
至少2字节
short
至少2字节
小于等于int
long
至少4字节
大于等于int
范围
超位
回到另一端定理
int16位
有符号

无符号
后缀
l或L
u或U
ul
浮点
默认类型
double
限制
位数限制
float
6位有效数
double
13位有效数
long double
至少和double一样多
范围
-37~37
精度丧失位
假显示
精度只能保证已写的位数
失去精度的位置
特点
实际已经不存在了
无法进行算术运算
由伪随机数替代
未失去精度的位置
已写的部分是确定的
未写的部分是未知的
没写的部分未必是0,可能是9
后缀
f或F
l或L
防止科学计数法输出
数值格式转换
转换
避免科学计数法
显示三位小数
还原
字符(无内容,参考用)
类型
普通字符
转义字符
c++字符(很少用)
wcha_t
定义
自定义拓展字集,超过1字节
使用
L'字符'
扩展字符集
将字符P的宽版本存到变量bob中;并打印宽字符串tall
输入输出
wcin
wcout
wcha_t类型的常量
L'字符'
char16_t/char32_t
用定长表示拓展字符
16位无符号/32位无符号
定长拓展常量表示
用前缀u表示char16_t的字符或字符串常量
用前缀U表示char32_t的字符或字符串常量
字符串
类型
4种常规
字面量
字面量地址
指的是第一个元素地址
数组
操作
字符串函数
查c表
初始化与形参
一维
初始化
数组法
int a[10]
指针法
char *pt
int ar[]
形参
指针法
int * ar
int ar[]
二维
初始化
数组法
int a[5][5]
指针法
int *A[i]={}
int pt[][4]
形参
指针表示
int (* pt)[4]
一个指向了一个数组,该数组内含4个int值(而不是存4个一维数组的二维数组)
int pt[][4]
计算长度
sizeof
数组长度
注意区分数组名和指针的长度使用区别
strlen
字符串长度
string类
操作
字符串拼接
加法+
输入字符串
getline()
get(cin,A)
cin>>
=
string a="aka"
初始化与赋值
初始化
二维
string C[A]
赋值
一维
赋值
string=string
计算长度
类包含的函数
.size()
new(记着用delete)
new数组
new string
4种特殊类型
whcar_t
L
char16_t
u
char32_t
U
原始字符串
raw
R"( )"
字符串表示的就是自己
如\n就是\n,不是特殊字符
若希输出"(或者)"
R"+*( )+*"
让*(和)*变成自己
3种常规字符串读取内容
读到\0为止
右值
右值赋值的方式
右值一般是赋给临时的变量,然后临时变量赋给目标变量,随后丢弃临时变量与右值
两种常量
常量
操作系统的标准值
climits文件中的字面常量
常量也有类型,决定了读取的二进制位数
整型
改变常量类型(后缀法)
浮点型
改变常量类型(后缀法)
float
f或F
long double
l或L
字符型
c语言
字符常量用int存储,用ASCII转换
从int型常量中抽8位给ch
c++
字符常量直接是char型存储
表达式
类型转换
三种转换方式
隐式转换
两种转换
大转小
有问题
截断
小转大
没问题
强制转换
两种方法
括号法
<>法
auto转换
根据初始值自动转化
符号优先级
优先级
从大到小
(), . ,【!,++,--,*】,【*,/】,【+,-】,
逗号运算符<赋值<逻辑运算符(或,与)<关系<算术<一元运算符<()
一元运算符
包含
前缀
后缀
解引用
排序
*p++ ,*++p
区别
逻辑运算符
!>&&>||
运算顺序
左到右
右到左
=
一元运算符号
自加自减
++,--,sizeof
所有运算符同级别
优先级
共用对象
有
运算顺序定律
无
无影响
数组
旧内容
数组的指针
一元数组
初始化与形参
初始化
数组法
指定初始化器
指定一个元素初始化
特点
指定之后如果还有数字如31,30,31。则这些数组会从[4]之后填充
如果再次指定初始化,则原来的会被替换
花括号法
只可以在初始化数组的时候使用,数组赋值不可用
指针法
char *pt
int ar[]
只可在函数原型或形参中或初始化数组时使用(因为没有长度)
形参
指针法
int * ar
int ar[]
只可在函数原型或形参或初始化数组中表示
二元数组
初始化与形参
初始化赋值方式
数组法
花括号+指定初始化器
注意下标与数目的关系
指针法
int *A[i]={}
i为该数组的总行数,也是A指针所指的单元有五个元素
用该方法初始化能够保证每个元素所占用是不定的(类似于int a[]自动转化大小)。此方法空间利用率较高
int pt[][4]
只可在函数原型或形参中或初始化数组时使用(因为没有长度)
形参
指针表示
int (* pt)[4]
一个指向了一个数组,该数组内含4个int值(而不是存4个一维数组的二维数组)
int pt[][4]
指针的表示
数组法
指针法
复杂声明
()与[]比*优先级高;同级从左到右
声明
int * risks[10];
一维数组,存了10个指针
读法
[]运算符的优先级高于*,因此a先与[10]结合,a是一个具有十个元素的数组,每个元素是一个指向int型的指针
写指针进去
int (* rusks)[10];
二维数组。未知个数组指针rusks指向了一个内含10个int的数组
二维数组使用方法参考ONENOTE
只有长度,没有宽度的表示方式
若想表示宽度,应该是
读法
rusks是一个指针,指针指向10个int类型的数组
没有宽度;只可在形参中用
int * oof[3][4];
一个3*4的二维数组,存了12个指针
int (* uuf)[3][4];
未知个uuf指针指向一个3*4个int的一维数组
没有宽度;只可在形参中用
int (* uof[3])[4];
uof数组存了3个指针。然后这3个数组指针又分别指向3个包含4个int的数组
规定了长度为3;只可在形参中用
函数
char *fump()
fump是一个函数,返回char指针
char(*frump)();
frump是一个函数指针,该指针指向返回cahr类型的函数
char(*flump[3])()
flump是一个存了三个指针的数组,每个指针指向返回类型为char的函数
新内容
数组内容禁止缩窄转换
C++数组
vetcor
特点
动态长度
include<vetcor>
动态数组,运行时确定长度,可在过程添加新数据
使用
初始长度设为0,运行时自动变化
初始长度设为n,运行时自动变化
array
特点(对比普通数组)
可以通过=方式赋值
类数组,但可用于存储对象
静态长度
n必须为常量
const数组
不可用pe修改数值
不可修改finger的指向
数组的输入输出
输入
输入规则
输入内容
输入方法
cin
cin.getline()
cin.get()
检测错误并消除输入流
输出
cout
数组的地址
int tail[10]
tail
指向首元素地址
&tail
指向整个数组
&tail[2]
某个元素的地址
基本操作
循环
C++特性
判断条件
for针对数组,条件可以是范围
x开始表示数组第一个元素,随后不断循环不断向后执行
引用法可以直接修改本体
判断条件可以是表达式
表达式值是否为0
循环的副作用与标志
while
while()括号内部是一个完整的表达式,在进入cout之前实现了+1
for
在执行完for函数之后才会执行--n
前缀后缀格式
前缀后缀结果不会有区别。速度有区别
前缀格式
效率高些。将值加1,然后返回结果
后缀格式
先复制一个副本,然后加一,然后将副本返回
输入信息
错误输入
导致终止输入
解决方案
输入结尾检测
cin.eof()
检查EOF是否被设置
设置了就返回true
cin.fail()
同上
cin表达式自动返回bool的值
判断
if
switch
switch与枚举
switch的判断条件会把枚举自动化成int型
特殊函数(可看)
延时运行
ctime库中的clock()函数,返回clock_t类型
常量。每秒包含的系统事件单位数
秒数
系统时间单位为单位时间
特殊函数类型
typedef
给函数取别名
用处
克服#define针对复杂类型的缺点
只有pa转成了指针
enum
初始化
默认
0,1,2,3,4...
指定
后面的=前面的数+1
赋值
枚举不可以被不同类型常量赋值
可赋值
可被赋值
枚举可以被同类型赋值
不可大于枚举最大值
最大值为2^n-1,比枚举内部最大值大
默认为0.如果比0小,最小值为2^n-1,比枚举内部最小值小
可复制给别人
枚举可以赋值给别人
枚举是一种直接提供定义的函数,不像模板需要声明
共用体
能写不同类型,但能用的只有一个
快捷创建共用体变量
结构体
默认
初始化为公有的0
赋值
支持等号赋值
快捷创建结构体变量
文件操作
读写
使用父类头文件ostream和fstream
写入内容至文本文件
子类ofstream
步骤
创建对象
打开文件
打开文件名是字面量
字面字符串法
若文件不存在
重新创建文件
若文件存在
修改会丢弃原有内容
打开文件名是数组
写入内容至文件
关闭文件
读取文本内容
子类ifstream
创建对象
打开文件
文件必须存在
可以用is_open()检查
如果被成功打卡哎,返回true
打开文件是字面量
打开文件是数组
读取内容
读取文件内容
读取文件内容到wt中
读取文件内容到数组中
结尾检测
eof,fail,bad()
good()
关闭文件
函数
函数必须具有单定义性
函数与数组
参数
数组+范围
数组
形参
数组形参用数组指针表示
实参
传递地址
范围
数值范围
指针范围
形参
实参
元素数目
指针-指针=数目
函数与字符串
参数
string法
二维字符串
形参
函数与array
函数原型
实参
形参
指针
副本
使用
pa指向的时整个array对象
*pa直接对应了该array对象
(*pa)[1]指的是该array对象的i个元素
函数指针
单函数指针
可用(*pa)代替函数名使用
多函数指针
指针指向三个函数
函数的名称修饰
每个函数即使重载了也有不同的名称修饰来区分
如
C++函数特性
三种C++函数
内联函数
作用
减少函数间执行需进行的跳跃
使用
inline
内联函数不像普通函数一样
内联函数不受单定义性规则
包含了头文件的每个文件都有内联函数的定义
函数重载
通过函数特征标区分函数
形参
形参数目;形参数据类型
const与引用无法区分重载
使用重载
完全匹配
只有一种
数目,类型全部对上
判断
模板,显示函数,函数优先级关系
不匹配
优先级判断
形参数目
类型转换
强制
隐式
模板
模板的方案规定
两种分类
标准模板(默认)
不用管形参数据类型的通用函数
使用class和typaname是一样的。只是class式老版本
模板自身无法生成函数定义,只是用于生成函数定义的一个方案
实例化
使用模板生成特定类型函数定义时得到的是模板实例
使用
定义模板函数
template <typename 模板名>
模板名会在被调用模板后自动转为用户定义的类型
定义
定义时,形参不一定都是模板类型
模板重载
区分
形参数目;形参形式(如指针,引用);
显示具体化(特定)
作用
为模板创建特定的具体化模板满足特殊需求
根据输入参数类型来判断是否是显示具体化
使用
template<>void Swap<类型>(类型1,类型2)
<类型>是强制转换参数类型。如果需要可以有,不需要可以不带
模板的定义
实例化(即模板的具体定义)
作用
模板没有定义,实例化则是模板的特定定义
显示实例化
声明
根据作用域来写
<>可以让参数强制变成我们需要的
使用
Swap(a,b)
其中a,b是int型
Swap<int>(a,b)
a,b被强制转为int型
隐式实例化
让程序自动判断参数的类型
模板,具体化,函数同时存在时
优先级
非模板优先与具体化;具体化优先于模板
<>
函数参数类型强制转换符
2种新函数参数
引用
特点
主针对对象
相当于给目标取了一个别名,动态变化
与指针相比
引用必须初始化,且指定后后续无法更改
类型
左值引用
&
使用
声明+初始化
函数
形参
实参
传递变量或对象
问题
传递的是右值
传递的类型不匹配
解决
形参用const即可
实质是引入了副本,失去引用的意义
相当于传递的类型不可以不匹配
返回引用
传统返回
本质
数值复制到临时的变量,然后临时变量赋值给调用函数,随后删除临时变量
返回结构的话就要把全部复制了
引用返回
本质
引用赋值给了调用函数
注意局部变量(避免函数执行完后自动删除的变量)
避免返回局部变量的引用
避免返回指向局部变量的指针的引用
应返回的引用
形参,外部
动态变量
引用类型必须引用的是左值。数组名不是
引用类型不能用于数组名
右值引用
&&
总结
可传递
r1
可修改左值
r2
可修改左值;const左值;右值
r3
右值
默认参数
输入默认参数的部分不需要输入参数,如输入了覆盖默认参数
函数原型中写出
默认参数必须从左到右,不可选择指定位置为默认
用于检验new的边界
函数搜索规则
优先搜索用户定义的
如果没找到搜索库函数
静态的使用
本文件中寻找
非静态的使用
程序文件中查找;没找到去库函数找
模板
特殊类模板valarray
声明与初始化
valarray+数据类+对象名+(多种类型构造函数)
可以创建空数组
可以创建指定长度数组
指定长度,所有元素被初始化指定值的数组
用常规数组的值进行初始化
直接初始化
方法
类模板(本质上就是个类,特征和类是一样的。可以写在.h,也可以写在.cpp。但定义和声明要写在一起)
创建类模板
参数
格式
未含表达式参数
template<class 类型>
可用class,也可用typename
含表达式参数
右边为表达式参数int n
实例化时传参必须是常量,且无法被修改
只能用整型,枚举,引用,指针类型
含默认值参数
模板类参数类型
参数必须填入模板类
必须填入模板类,并将自己实例化为实参的类模板
存在模板king
填入king类模板的模板对象neula
crab<king>neula;
成员Thing<int>被实例化为king<int>
成员Thing<double>被实例化为king<double>
在crab模板类中使用了Thing类型的成员会被被实例化替换成king模板类
class/template T
万用类,也可直接填入模板类
使用了类型为ArrayTP<int,5>类型的类模板作为参数
10个元素的数组,每个元素有5个int
表达式参数n
右边为表达式参数int n
实例化时传参必须是常量,且无法被修改
只能用整型,枚举,引用,指针类型
声明定义类模板
类模板的声明与定义应该写在同一个文件夹下
声明
定义
定义模板的函数
template<class 类型>
使用
声明具体化模板对象
类声明数取决于模板的参数,只要参数不同,就是另外一个独立的类
常规
默认构造函数
将会生成两个独立的类声明
调用构造函数
声明类模板数组类型并初始化
指针
注意要创建空间再指向
栈应该是负责管理指针,而不是创建指针
应该让调用程序提供一个指针类型的数组。每个指针指向不同字符串
模板实例化/具体化
模板只提供了算法,但没有占用具体的内存,需要实例化或具体化
实例化
隐式实例化(常用,但必须被使用才会生成对象)
对象即使声明了也不会被实例化。只有被使用了才会被隐式实例化
显式实例化
template
没有提及对象,但也生产了类实例化
具体化
针对特定的参数类型进行的特定操作
template<通用类型>class pair<特定类型>
完全具体化
格式
部分具体化
部分具体化限制参数
通过其他参数限制参数类型
使用时根据所写的声明最佳优先匹配
优先级
根据具体化匹配度从高到低
成员模板
模板内定义嵌套模板
模板类内有模板类
因为hold模板在私有成员内,所以只有该类能用
模板函数blab
U根据填入的数据来判断数据类型
使用
对象.模板
U为int
U为double
模板参数用作构造函数
实参来决定形参的数据类型
模板外定义嵌套模板
使用了几个模板参数就要定义时写几个template
hold
将所需的类型与自身所属类的数据类型写出
blad
模板类的数据类型
类模板自身也是一种数据类型,可以创建对应类型的对象
该情况类名是ArrayTp<类型,int>
模板类与友元
模板类的友元函数
非模板友元(不声明)
相当于普通的友元函数
两种类型
不带类型参数
全局有效,该友元是该模板类所有实例化的友元
模板类型参数
必须指明HasFriend的具体化,使之成为对应模板类的友元
如参数为HasFriend<int>,则代表模板类实例化int。此时该int情况的友元成为该int模板类实例化的友元
约束模板友元(在外声明)
模板是友元类型
友元类取决于在模板外部被实例化时的类型(外部确定类型后内部无法更改类型)。因此只有一种类型
步骤
在类外声明模板函数
在类中将模板函数声明为友元
对友元函数具体化
两种方法
<>中写出类型
counts<TT>
参数中告知类型
report<>
提供定义
非约束模板友元(在内声明)
一个友元实例化,一个独立的的类型
每次友元函数具体化都是对应类的具体化的友元
内部声明能让友元具有多种类型
步骤
在类内部声明模板友元
定义
使用
两次具体化友元函数,生成两个不同模板类的友元函数
模板类与静态成员
每一个模板类的具体化都有一个自己的静态成员
typedef与类模板
可以简化模板类的类型写法
友元与异常
异常(没总结完)
方法
中断执行
abort()
中断执行(一般发生错误默认执行该函数
该函数位于cstdlib头文件中
返回错误码
通过返回指针或引用来返回数值告知成功还是失败了(例如bool)
异常机制
模块化检查是否触发了特定条件的错误
通用模板
try,,theow,catch
try
尝试判断函数是否会出现异常
catch
针对特定类型进行特定处理
例子只能针对theow返回const char *s类型来进行处理,符合hmean中throw的返回
theow
若a==-b则发生异常,并返回一个字符面量。并直接跳到try块的后大括号}之后
theow返回的是副本。即使是返回指针引用类型,返回的也是副本
当没有遇到对于catch时。默认为执行abort
将对象作为异常返回类型
栈解退
theow直接退到try的后大括号
theow如果有try嵌套;则不断向上退到try
try嵌套含try
调用函数(优先级从内到外)
main中
mean中
throw;
该情况直接跳到try大括号后执行第一个catch
在mean中无bad_gmean()的catch。但main的try嵌套了mean的try,因此会向外寻找bad_gmean的catch
在main中找到catch后后续的代码show就不会执行了
类的层次关系
catch(基类)可以捕获返回派生类的异常对象
写catch应该把捕获派生放在最前面;捕获基类放最后面
bad_3 &be放在前面;bad_1 &be放最后面
如果捕获基类写最前面则会导致优先执行捕获基类的
默认捕获
只要发生异常就会捕获,虽然不知道类型
exception类
使用
C++可将其作为其他异常类的基类
使用例子
what()为exception的一个虚函数,返回一个字符串,该字符串的特征随实现而异
类型
stdexcept头文件类
类(从exception派生来)
logic_error
用于描述逻辑错误
domain
值域与定义域
invalid
指出给函数传递意料外的数值
length
指出没有足够空间执行所需操作
out_of
索引错误
runtime_error
运行期间发生难以预计和防范的错误
range
提供一个供方法what()返回的字符串
underflow
下溢错误
overflow
上溢错误
继承关系可以一起捕获并处理这些异常
利用exception头文件中的异常类在同一基类中捕获他们
异常类与继承
异常类支持嵌套,派生,继承
RTTI(只适用于包含虚函数的类)
作用
运行阶段对对象类型进行识别
RTTI的元素
dynamic_cast运算符
定义
dynamic_cast运算符将使用一个基类指针来生成派生类指针;否则该运算符返回空指针
作用
用于回答是否能安全的将对象地址赋给特定的指针
必须基类指针引用指向派生类才是安全的
例子
P1安全,P2不安全,P3安全
运算符的实际使用
指针
对象pg若可以被安全转换为superb*型,那就返回该对象地址。否则返回空指针(取决于pg原指向的对象)
pg若指向的对象为superb或者superb的派生对象,则可以强制转换。否则为空指针
引用
类似指针,只是失败时引发类型为bad _cast类型的异常。该异常从exception类派生来,在头文件typeinfo定义
判断
用于判断是否安全转换
typeid运算符
返回一个指出对象类型的值
作用
能够确定对象是否是同种对象
使用
接收两个参数
类名
结果为对象的表达式
返回
typeid运算符返回一个type_info对象的引用
通过==和!=来进行类型比较。该运算符为重载,返回bool
相同为true;不同为false
若pg为空指针,则引发bad_typeid异常
一边为类型;一边为对象
例子
type_info结构
存储有关特定类型的信息
类型转换运算符
为强制转换类型添加限制
dynamic
只允许朝着基类强制转换
const
让const性质暂时删除
pb可以修改bar对象的指针
只允许const或volatile特征不同,其他的type_name和expression必须相同
static
只有type_name可以隐式转成expression类型或者expression类型隐式转成type_name类型时才合法
reinterpret
string类与STL泛型编程
string类
本质
string类实际是模板类的具体化base_string<char>的一种typedef
string类独有内容
string::npos
字符串最大长度。决定了string的最大长度,即使是自动调整大小
通常为unsigned int最大值
格式
string构造函数
NBTS表示以空字符结束的字符串
(const char*,int n)
如果n超过char的最大长度,则会导致有空字符被复制到string对象
移动构造函数
(string&&str)
导致新创建的string为str副本
与复制构造函数不同的是,不保证str视为const
输入
string类输入
两种
cin>>string对象
getline(cin,string对象)
(可自动调整大小,但不会超过string::nope)
输入读取结尾
文件结尾
fail()和eof()都返回true
分界字符(默认为\n)
不存储分界字符
string::nope
fial()返回true
输出
cout
string操作
对string赋值
运算符重载法
成员函数法
连接两个string
运算符重载法
成员函数法
比较字符串(大于小于或等于)
按照ASCII比较
string与char
string与string
char与string
元素数目
size()
搜索字符串的位置(返回位置)
find
pos=0
从0号位置开始查找
没找到返回-1
其他(与find特征标相同)
rfind
查找字符串字符最后出现的位置
find_frist_of
查找字符串字符首次出现的位置
find_last_of
查找字符串字符最后出现的位置
find_frist_not_of
查找第一个不包含在参数中的字符
find_if
替换字符串
获取或写入元素
at
插入或删除
获取子串
截取string当中一小段作为子串
自动调整大小
为防止占用相邻内存,会分配一个新的空间;并且为减少分配次数,一次性分配的内存会比实际大(最小提升到15个字符)
智能指针模板类
需包含头文件memory
定义
针对动态内存。普通指针生命周期结束后会被删除造成内存溢出;智能指针是对象,生命结束时调用析构函数删除指针指向的内容
类型
auto_ptr(几乎不用了)
内容
auto_ptr<double>
一种模板具体化,一种类的类型
返回的<>内类型应与实参类型相同
new double
实参,构造函数参数。对应了指向的位置
其构造函数全为explicit。不支持其他数据类型隐式转为该类型
遇到赋值情况会忽略。有隐藏风险
使用new/delete
unique_ptr(与auto_ptr一样,但更安全)
遇到智能指针赋值情况会打断
有使用new[]和delete[]/new和delete版本
shared_ptr
使用new/delete
包含一个单参显示构造函数,可将右值unique_ptr转为shared_ptr
等号问题
一个智能指针指向另一个智能指针
为避免导致对一个对象析构两次,会采取
所有权转让
ps将所指对象的所有权转交给vocation
auto_ptr(不常用)
会继续运行,无法识别隐藏的错误。不安全
unique_ptr
为防止后续使用之前被转让权力的智能指针。直接使其错误防止被转让的智能指针存在于内存中
缺点
如果转让后再使用之前的智能指针,则会发生错误
计数策略
赋值时,计数+1,指针过期时,计数-1。当计数为0时才调用delete析构该对象
STL
特点
泛型编程
面向对象注重数据;泛型编程注重算法,希望用更通用的方式表达容器
算法要通过迭代器才能访问容器
不同容器有各自的迭代器
通用的算法模容器+迭代器具体实现(迭代器具有不同的特征)
STL标准模板库包含的6大组件
容器
用处
存放数据用的(类似数组)

结构类型
序列时容器
位置固定
关联式容器
可能会重新排序
存储的数据必须是可复制可赋值的
容器特征
复杂度
C++11新增
移动构造函数可以修改源对象,转让所有权
容器种类
序列容器
特点
迭代器至少是正向迭代器
线性排序,前驱后继
顺序是固定的,插入顺序是什么容器内容顺序就是什么
序列的要求
insert
将原始区间的副本插入到目标地址
splice
原始地址区间移到目标地址
可选要求
类型
vector
性质
动态空间数组。满了就删除旧的空间新开一个更大的空间
测试
新的空间起始地址也不同了
特点
强调随机访问
支持随机访问迭代器
格式
构造函数
vector操作
访问
序号
赋值
=
assign
交换内容

反向迭代器rbegin和rend
ri迭代器指向dice容器的起始元素
vector专用的成员函数
rbegin
返回超尾的反向迭代器
rend
返回第一个元素的反向迭代器
vector容量和大小
插入和删除
添加元素到末尾
push_back()
删除给定区间内的元素
erase
第一个未开始,第二个为超过容器结尾
指定插入位置
insert
第一个指定old的插入位置;第二个第三个指定了new的插入区间
数据存取
vector预留空间
功能
用该函数扩大容器的最大容量来减少自动扩容的次数
reserve
find
find_if
按条件查找
分配器(管理内存)
deque
特点
双端队列
支持随机访问
原理
中控器管理缓存区地址,按顺序存储;缓存区存储数据
使用
构造函数
操作
赋值操作
大小操作
插入和删除
数据存取
list
特点
双端链表
强调删除插入
地址的存储无顺序
不支持随机访问,修改一个必须移动其他的元素
使用
构造函数
操作
、
unique
相邻的同值压缩成单值
sort只能用于随机访问迭代器。因此不能用于链表
赋值
大小
插入和删除
数据存取
无中括号和at
反转和排序
不支持随机访问迭代器的容器不支持通用算法,所以不能用sort(a.begin,a.end)
两种格式
sort()
sort(bool排序规则函数)(针对对象使用)
list工具箱
list方法组成了list工具箱
forward_list
单链表。单向迭代器
queue
队列
不允许随机访问;不允许遍历队列
priority_queue
队列,最大的元素放到队首
stack
特点
栈的规则
操作
array
长度是固定的
关联容器(注意自定义类型)
特点
数据插入容器后排序会重新排序
可用于快速访问
将值与键连接在一起,并用键查找值
表达式
类型
set.h
set
值的数据类型和键的相同,且键是唯一的。不允许有重复的值
使用
构造函数
<>内参数
数据类型
指示对键进行排序的函数或对象
修改仿函数法修改()符号来修改set自动排序规则
逆序排序
插入时调用()重载,按照该重载规则排序
可选,默认为less<>
自定义数据类型需要用到仿函数
set构造函数指明了使用参数表示区间。用迭代器表示参数
操作
赋值
=
插入与删除
返回pair
大小操作
查找与统计
返回迭代器
其他排序
创建容器时用仿函数实现
multiset
类似set,但可能有多个键的值相同
操作
类似set
插入操作
返回iterator迭代器(鼠标右键转到定义可查看)
set与multise区别
map.h(按照键来自动排序)
mutimap
类似map,但一个键可以与多个值关联
map(针对元素都是pair模板类型)
特点
值与键类型不同,但键是唯一的
所有元素都是pair。元素都是成对出现:键与值
使用
构造函数
T1,T2表键和值
修改排序规则
通过函数对象的返回值来修改(map可以通过接收bool来调整顺序)
操作
赋值
大小交换
插入删除
插入pair类型(可用匿名方式插入)
第四种方式根据Key来寻找值并插入
如果key不存在会重新创建一个未知的
若填入pair参数类型不准确,会提示有与参数列表匹配的重载函数和传局部变量地址问题
不允许插入重复的key
查找和统计
cout要么0,要么1
改变排序规则
仿函数法
遍历
用迭代器!=end作为判断
容器嵌套容器
创建容器
该容器的元素是容器
操作
插入
遍历
算法
质变算法
会修改元素的数值
非质变算法
不会修改元素数值
算法函数
若非成员函数与成员函数同时存在
优先成员函数
通用算法函数
(头文件#include<algorithm>)
for_each
头文件
#include<algorithm>
将被指向的函数应用于容器中的所有元素,但不能修改元素值
三个参数。前两个是定义区间的迭代器。最后一个是函数对象或函数
参数对象用仿函数表示
普通函数用函数名;仿函数用函数对象
transform
一个容器内容搬运到另一个容器
格式
可以先进行运算,再搬运
find
类型
find
查找目标
查找内置类型
查找自定义类型
find_if
三个参数,按条件查找
两个表范围;第三个用真假,可用仿函数表示
查找目标
内置类型
自定义类型
adjacent_find
格式
查找到,返回相邻元素第一个元素迭代器;若无则返回end迭代器位置
查找
binary_search
必须有序
返回值为迭代器
排序
sort(a.begin,a.end)
如果是对对象进行排序,则要写排序规则函数指明对对象的哪个成员进行排序
两个版本
升序(默认)
接收两个迭代器表区间。并使用容器中的<运算符
默认进行升序排序
若容器元素为对象,则需要有能够处理对象的operator<()函数
默认使用less<>的函数对象作为第三参数判断bool
降序
仿函数实现降序
random_shuffle
随机排列容器中的元素
两个参数,指定区间的迭代器
merge
两个容器必须是有序的,合并后还是有序的
reverse
copy
使用复制迭代器会替代以前的内容;使用插入迭代器则是将元素插入
三个迭代器参数
第一个第二个元素表容器内容的范围;第三个表拷贝到哪里
cout
cout
统计个数
格式
统计类型
统计内置类型
统计自定义数据类型
cout_if
格式
统计类型
统计内置类型
统计自定义数据类型
replace
replace
replace_if
swap
两个容器类型必须相同(如vector必须和vector互换)
头文件#include<numeric>
算术生成算法
accumulate
计算区间内元素总和
value为累加初值。一般为0
fill
向指定区间填充元素
集合算法
set_intersection
将交集放到新容器里;返回一个迭代器
set_union
set_difference
具有相对性,第一个容器比第二个容器多余的
注意,如果要显示则取的for_each范围是迭代器
迭代器(广义指针,访问容器内容需要用迭代器)
用处
连接容器与算法的桥梁
容器中的通用数据类型。用于通过迭代器对通用泛型的具体表现(类似于模板中的数据类型T)。不同的迭代器会对数据造成不同的操作
特征
迭代器按照功能分类
五种迭代器(使用时尽量选要求低)
输入迭代器
读取容器信息但不修改值
单通行,解引用后不能保证前值还能被解引用
遍历的顺序未必相同
输出迭代器
将信息传给迭代器,但不可修改值
单通行
遍历的顺序未必相同
正向迭代器
具有输入输出迭代器性质;与输入输出迭代器相似
不同的是遍历顺序相同
既可以读取,也可以修改
双向迭代器
具有正向迭代器的性质;并支持前缀后缀两种递增递减运算
随机访问迭代器
全部都有
模型
对迭代器具体的实现(如指针或对象)叫模型
类指针迭代器指向表示元素迭代器
迭代器类型例子
不同的迭代器类型具备不同功能(根据功能级别来选择)
5种类型
通用迭代器
指向起始/超尾元素的迭代器
迭代器.begin/end
头文件iterator
格式
容器类名::迭代器类型
迭代器类型(会改变数据的操作方式)
复制迭代器(用iterator创建)
iterator
正向迭代器
reverse_iterator
反向迭代器
使用递增操作会导致递减
对已有的递增函数来反向显示内容
ri迭代器指向dice容器的起始元素
vector专用的成员函数
rbegin
返回超尾的反向迭代器
rend
返回第一个元素的反向迭代器
插入迭代器(用模板创建)
back_insert_iterator
容器尾部插入
front_insert_iterator
容器前端插入
不适用于vector容器
insert_iterator
插入到insert_iterator构造函数参数指定的位置前面
只读迭代器
const_iterator
常规指针(复制迭代器)
模板
输出迭代器
ostream_iterator
该迭代器可以把内容发至输出流中,并用空格作为分隔符
容器为参数的迭代器
需要使用合适的容器方法
构造函数参数为容器标识符
容器标识符dice
参数为容器标识符,插入位置
对象
迭代器表区间
两种方法
一个表起始位置;一个表超尾
使用输出迭代器拷贝
注意!!!超尾指针不能被解引用
起始位置
检测空指针即可
输入迭代器。第一个表示要读取的数据类型,第二个指出输入流使用的字符类型。
直到文件结尾;类型不匹配或出现故障为止
迭代器操作
自加自减
自加自减
重载
前缀
operator++
后缀
operator++(int)
解引用
对iterator迭代器解引用的话看尖括号里是什么,解引用出来就是什么
仿函数(函数对象)
格式
定义
对()进行重载
使用
创建对象的格式
用类的方法写出。但主要重载了(),并通过()来表示对象,最终成为函数对象
函数对象
重载函数调用操作符的类,其对象为函数对象
针对自定义数据类型时可以使用仿函数来指明操作的成员
例子
容器
非关联容器
对函数用
关联容器set
容器定义时用
第二个接收bool类型值
通用函数
sort,find_if
特点(重载了()的特点)
使用返回值
使用状态
定义仿函数
调用仿函数
使用参数
内建函数对象(系统已经存在的()重载)
头文件functional
类型
算术仿函数
四则运算
取反(一元)
加法(二元)
关系仿函数
大于
逻辑仿函数
适配器
空间配置器
Pair对组
定义
创建
谓词
返回bool类型的 仿函数
一元谓词
如果operator()接收一个参数
如find_if
二元谓词
如果operator()接收两个参数
如sort
基于范围的for循环(用于STL而设计的)
从开头到结尾
不同于for_each,该循环可修改容器内容(使用引用的方式)
类的特殊用法
类的继承
基类与派生类
基类
特点
多态性
基类的指针引用对象可以指向派生类对象;但不能调用派生类方法
可以创建一个基类指针的数组,既能指向派生类,也能指向基类
析构函数
基类即使不需要析构函数,也应提供一个虚析构函数
确保派生对象可被析构
继承与调用
基类的构造函数,赋值运算符,析构函数不会被继承;只会在需要时被调用
继承相当于派生也有一个与基类完全相同的函数
调用相当于调用基类的函数,不是继承
派生类
特点
派生类对象能使用基类的方法;但不能直接访问基类的私有成员
创建派生对象时
必须给派生成员和基类成员提供数据(此时基类必须有构造函数)
初始化列表法(只可在构造函数中用)
顺序
先调用基类构造函数
后调用派生类构造函数
派生构造函数看起来可能有多余的部分参数(输入的参数比派生类成员数多),但实际上这是用来初始化基类对象的
无初始化列表,则使用默认基类构造函数
派生类对象
创建派生对象时先基类后派生
先创建了基类的对象,然后创建派生类对象
因此派生对象存储了基类数据成员
但不能直接访问基类私有成员。需要用基类方法作为接口
可以使用基类的方法,但不可直接使用基类私有成员
派生类方法与构造函数可以使用基类对象为参数
格式
冒号后为public基类
赋值运算符(必须对所有成员)
无赋值运算符定义
调用基类的赋值运算符
只会处理该派生对象的基类成员,不会处理新的成员
定义了赋值运算符
则必须对所有成员提供赋值运算符
基类成员
派生类成员
使用
基类对象=派生对象
可以,但只对基类成员处理
派生对象=基类对象
构造函数
带着基类的成员一起初始化
析构函数(必须对基类于派生类)
顺序与构造函数创建对象相反
先调用派生的析构函数,然后自动调用基类的的析构函数
基类与派生类的方法
同名函数下
不虚,则根据编译器执行时所读取的类型来判断;若基类函数为虚函数则是在程序执行时判断真正的对象类型
多态公有继承
虚函数virtual
同名同参的方法,在基类和派生类中行为不同。能忽略指针类型,跟踪到对象真正的类型来调用函数(动态编联)
动态联编
真正对象的类型只有程序运行时才知道
原理(可看)
编译器处理虚方法时,给每个对象添加一个隐藏指针成员
该指针成员指向虚函数表数组
数组中存了基类和派生类方法的地址
派生对象一个指针,基对象一个指针。分别指向不同的虚函数表数组
未重新定义的
重新定义的
新函数的
调用虚函数时,程序将查看对应的对象的隐藏指针
虚函数的使用
声明
基类设定为虚方法
派生类创建对应同名的方法
可将同名方法也设定成虚方法,也可以不设(但最好设)
派生重载基类
基类函数与派生函数同名
派生对象只能使用自己的,不能使用基类公开的
虚函数使用范围
普通函数
同名同参但不同内容的方法用virtual
析构函数
基函数的虚析构函数
能确保对派生对象也执行虚构
先对派生对象执行析构,然后对析构基类对象
若基类析构不是虚的,则不会根据多态性进行析构,而只会根据指针的类型进行虚构
若析构为虚函数,则会根据基类指针指向的对象的类型来进行析构
构造函数
不能是虚函数
友元
友元不能是虚函数。因为友元不是类成员
赋值运算符
不是虚函数
因为基类的赋值运算符与子类赋值运算符形参不同,不是同一个
函数中的形参
引用或指针型形参会受到虚函数的影响,按值传递的不会
若形参为基类指针或引用
传递的实参对象类型也产生隐式向上转换
使调用函数是实际实参的类型
若形参为基类对象
按值传递
调用的函数类型是形参的类型
若希望既执行基类的内容,又执行派生类的内容
基类方法为virtual前提下,派生方法定义中写基类方法
若派生类中没有定义同名的方法。则不需要作用域解析运算符
静态联编与动态联编
分类
静态联编
编译时选择要执行的函数内容
无虚函数时用静态编联可提高运行效率
动态联编
程序运行时选择需要的函数内容
与虚函数关系
静态联编
对于虚函数非常困难,因为编译器不知道用户选择哪种类型对象
动态联编
若存在虚函数则必须需要动态编联
需要一些内存来跟踪指针或引用所指向的对象
抽象化继承
概念
寻找两个类共同的特点,并将这些特性放到新类person中,然后从新类派生出两个类deafperson和blindperson
抽象基类
基类里至少存在一个纯虚数
纯虚数
虚函数=0
作用
被标注纯虚函数的函数其功能必须由子类实现
保证了函数功能不与父类重叠
只是为了防止忘记重名函数设定多态性
抽象类不能被实例化,只能作为一个基类使用
抽象化
寻找共性
共性中可能存在相同点,可能存在不同点
吃行穿是相同
看和听是不同点
不同点用虚函数表示用以区分
不同点用纯虚数来限定只能作用于基类
纯虚数需要提供函数定义
抽象化的函数可以不提供函数定义;也可在定义文件中来定义
若基类不提供纯虚数的定义,则子类无法实例化
若子类希望实例化纯虚函数,则必须额外提供函数定义,否则会出错
使用
用基类类型BaseEllipse的指针或引用来指向两个派生类的对象
实例
私有成员也要写(这里string写错了)。根据共性函数所需的成员来写
ABC类也必须写构造函数
只要是类就必须写构造函数
派生类构造函数需要引用基类构造函数,将基类构造函数成员填补
共性
相同点可以用ABC类来定义,可在定义文件定义,简单的可以在这里定义,默认为内联函数
不同点在不同的派生类中定义。且在ABC里要写成纯虚数
用指针和引用的方式来指示派生类
继承与动态内存
类型
基类成员使用new,则基类自身需要有复制构造函数,赋值运算符,析构函数
派生类不使用new
派生类不需要显示定义析构函数,复制构造函数,赋值运算符
因为此时派生类对象不需要显式调用这三种函数,只需要默认的就行了
派生类使用new
必须为派生类显式析构函数,复制函数,赋值运算符
派生类对象无法使用基类的析构函数,复制构造函数,赋值运算符
析构函数
调用基类析构和派生析构对派生类构造函数进行清理
对基类对象清理
用基类的析构函数
对派生对象清理
用派生类的析构函数
复制构造函数
派生类复制构造函数也需要调用基类的复制构造函数baseDMA(hs)
因为hs是const hasDMA&,const baseDMA可以指向hs并调给基类复制构造函数(基类可以指向派生对象,只不过使用基类函数对派生对象的话,只对基类成员进行修改)
赋值运算符
派生类必须有自己的赋值运算符。若希望将基类的赋值运算符包含则可以
在函数形参中,基类的指针和引用是可以指向派生对象的
可用于复制构造函数,赋值运算符等
若使用的是基类的函数,则只会针对派生对象中的基类成员进行操作
若使用的是派生的函数,则会回调派生的函数。回调的派生函数又会回调基类函数。递归操作
基类指针引用的指向和使用的函数是两件事(重点)
基类指针和引用指向派生对象
范围是所有成员
派生对象中包含派生成员和基类成员。
使用函数
使用函数局限了对成员进行操作的范围
派生函数
只能对派生成员进行操作。除非派生类函数里带上基类函数(因为派生对象不能使用基类私有成员)
基类函数
只能对基类成员进行操作
派生类访问基类友元函数
友元属于哪个类,就能访问哪个类的成员
使用哪个友元
使用时可通过强制转换来选择使用哪个友元
根据使用的参数类型来选择友元函数
派生类对象使用基类的方法
函数功能表总结
只要是个类就必须有构造函数
const char*与char*const
const char*可以更改指向
char* const可以更改内容
is -a模型
派生是基类的一种
派生类要完全继承基类的原貌
将基类的公有成员传递给自己的公有方法里
香蕉是水果,并且香蕉有自己的特性
代码重用
嵌套,包含,私有继承,保护继承
嵌套类
类B中包含类A的声明
类似与包含,但不同于包含
包含使用的是类的对象
嵌套是直接在里面声明
特点
B内包含A
B可以创建和使用A的对象,并使用其A私有保护成员;但对于A私有和保护成员不会对外公开
步骤
声明
next(0)为指向空指针;0可用nullptr代替
使用
用指针来调用嵌套的成员
嵌套类作用域
若被嵌套类是在另一个类私有部分声明,则在该类中只有后续成员知道它
若被嵌套类是在另一个类保护部分声明,则在该类中与派生类知道它。不对外公开
模板类嵌套
在模板中嵌套类
包含
定义
类的私有成员包含了类的对象
特点
总类可以使用包含成员对象的实现(方法),但没有继承该对象成员的接口(对外开放)
通过被包含的类的对象
name,score
格式
私有成员
被包含的私有成员有类对象
非公开继承
student类外没有将string和valarray的方法对外公开。student类内可以通过对象name和score访问string和valarray的方法
公开继承派生类能继承基类的方法,并且将其对外公开
构造函数
初始化被包含的类成员对象
初始化列表法
初始化顺序
与成员被声明的顺序一致
括号内对应着成员对象的类型的构造函数
name(str)对应string(const char*)构造函数
方法调用(调用成员对象的方法)
对象名.方法
私有继承
定义
基类的公有成员保护成员都将成为派生的私有成员
派生类只可使用,不可将其公开
私有继承可以多重继承,公有会出现很多问题
特点
格式
private可写可不写
继承内容
通过无名对象的方式继承了基类的公有成员与保护成员(隐式继承)
格式
基类对象
因为不存在显式的基类类型对象,但又希望返回该类型对象
强制转换
因为string是student的基类,所以可以强制转换(基类有的派生类都有)
构造函数
初始化隐式继承的成员
:类名(数值)
调用基类的构造函数
方法
调用基类的方法
类名::方法
若希望公开基类的方法,可以重新定义一个方法来公开
访问基类友元函数
强制转换
stu将调用string中的输出友元函数
若不强制转换,则会导致递归调用,函数内继续调用该函数无限循环
保护继承
使用
protected
特点
基类的公有成员和保护成员都将成为派生类的保护成员
包含与私有继承的相同与区别
区别
使用方面
包含
通过显式的对象名name来表示student继承了string的成员和方法
私有成员
通过无名对象的方式继承了string与valarray的公有成员与保护成员(隐式继承)
相同
二者性质相同
都是总类只能使用其方法与成员,但不能对其公开,全部私有化
都可以创建has-a
保护继承与私有继承区别
私有继承
第三代类不能使用基类的接口
保护继承
第三代类可以使用基类接口
重新定义继承关系访问权限(不可用于包含)
using
让类外也可以使用基类的公有成员
student类外也可以使用valarray的公有成员
将使所有版本都对外公开
多重继承(公有继承的情况)
特点
singing waiter类的对象会有两个worker副本,从而造成二义性
虚基数
定义
使singer和waiter公用一个worker对象
格式
singer于waiter的
共享worker类对象副本
singingwaiter的
声明
singingwaiter对象只包含一个worker副本
构造函数
应避免用初始化中间类来初始化基类worker,因为这样会冲突
错误写法
只能传递waiter和singer的私有成员量,不能传递wk对象的量。且此时自动调用worker默认值来初始化
方法调用
公有方法
singer和waiter和worker公用了方法show和set
singingwaiter必须定义show和set,否则产生二义性
错误写法
调用两次worker的show
只使用一次worker的show
模块化辅助函数显式
singingwaiter的show里单独显式worker的show
对辅助函数进行限制protected
可用保护来限制data方法仅供派生类使用而不允许对外
同名方法优先级问题
派生对象而言,派生方法优先基类方法
虚基数与非虚基数混合
例子
B是C和D的虚基类
B是X和Y的非虚基类
M从CDXY派生
M从C和D继承一个B类对象;从X和Y分别继承B类对象
M共继承3个B类对象
确保单定义性
#ifndef/#endif
C++新特性
内存模型
一套完整的程序3部分
头文件.h
内容
函数原型
宏定义const或define
结构的声明
类声明
模板声明
内联函数
避免头文件重复使用
当之前没有用预处理器编译过#define时才使用中间语句
保证使用一次头文件
使用该语句时定义#define即可
定义文件.cpp
相关内容与定义
主函数.cpp
存储
存储说明符
auto
显示地指出变量为自动存储
extern
引用外部变量
定义外部变量
可省略
区分
定义只能有一次。所以定义好后之后同名的extern都是引用
static
内部连接性
无连接性
thread_local
变量持续性与其所属线程持续性相同
mutable
即使结构变量为const,某个成员也可以被修改
存储位置
栈
栈定义
函数被调用时,实参加入到栈中。重新设置栈顶指针
结束后栈中数值不会被删。栈顶指针重新指向调用前的位置。只有下次再使用时栈中数值才会被替换
栈类型
自动变量
静态变量
初始化
默认初始化为0
自动转为动态初始化
如果右值需要编译执行时才能得出
注意范围和单定义规则
堆/自由存储区
new/malloc
delete()与new配合用
使用
定义
单值
数组
用new定义数组时必须带长度
初始化动态内存
初始化单值
括号法
数组与结构体与单值(大括号)
删除
new在堆区开辟数据
限定符
cv限定符
const
内部连接性
写在头文件中。包含的时候每个文件都有一个对应的const常量副本
范围是本文件
volatile
代理改变变量值,而不需要直接对目标变量改变(如时钟变量)
高速缓存
临时存储,需要时才从寄存器中提取
但如果代理变量导致源变量发生改变,将会导致其他代理变量发生影响。导致无法高速缓存
利用const可以让代理变量无法修改源变量
定位运算符new
指定特定内存位置分配空间
使用
包含头文件new
new()运算符提供所需地址的参数
含义’
起点位置为buffer1,从buffer1中分配空间给chaff
起点位置为buffer2,从buffer2中分配空间给包含20个元素的int数组
如需使用该地址,需要用(void *)buffer1强制转换
定位运算符所提供的地址参数是char类型指针
buffer1,2是char类型指针,最终显示为字符串
定位失败
new定位失败时
引发异常std::bad alloc
名称空间
用处
为了防止函数,对象,变量重名,所采用的特定标识
名称空间使用
定义名称空间
常规
namesoace 名字{}
可在命名空间里写出函数和结构和其他命名空间的定义。并使用
嵌套
使用命名空间
直接使用
::
简化使用
选择具体一个内容可简化(更推荐)
using 名称::内容
全部内容都可用(有潜在危险)
using namespace 名称
使用嵌套
直接使用
简化
赋值
相当于给空间名称换变量
未命名的名称空间
类似内部静态变量,范围受限于本文件
面向对象和类
面向对象原理
对象
具体个体
类(一般首字母大写)
数据成员
描述对象
私有(默认,可以不用写private)
只能通过公有的类方法间接使用数据成员
具备类作用域。只有在同类里的成员才能使用
类方法
具体的行为与操作
公有接口
通过对象.公开访问公有接口
(可根据需求设置成私有)
需求取决于希不希望使用方可直接使用该函数
成员函数
面向对象编程写法
头文件1.h
确保单定义性
#ifndef/#endif
头文件的内容
私有
类成员
公有
析构函数
自动的删除对象
如new的自动调用delete。遇自动变量时什么都不做等待大括号自动删除
使用
类名前加~
可以编写函数
变量对象被删除则执行该函数
类成员初始化的原型
默认法(防止冲突,二者不要同时存在)
默认无实参
默认无内容
当主函数调用对象不写初始化内容,默认为
默认隐式初始
构造函数+默认值
类的构造函数
通过构造函数给成员传值
避免形参与成员名同名
在成员名后加_,或者在前加m_
类方法的函数原型
公有的类方法
普通函数原型
私有的类方法
内联函数
类声明中的函数且在本文件有定义的都自动转为内联函数
类声明是头文件1.h
内联函数要求每个使用它的文件中都对他进行定义
也可以在类声明之外的成员函数化为内联函数
inline即可
两种方法是等价的,只不过一个函数定义写在里面,一个写在外面
类函数的私有函数定义
私有函数的定义写在这里就行了,因为不想让客户直接使用
类的作用域
范围
类内可知,类外不可知。要使用类必须通过对象
外部使用公开成员所用的符号
.
->
::
创建类作用域的常量
该常量只能在类内使用
不可用const
类只提供描述,不提供创建对象变量。因此没有创建常量
可用
枚举
该方法不会创建对象与变量,只创建常量
作用域为类的枚举
该方法不会自动转为整型,需要强制转换’
防止由于作用域原因导致冲突
static
头文件2.h
类方法与成员初始化的定义
默认
纯默认
无内容
内容直接定义初始化
默认参数
输入型
需要自己输入
可用::来标识函数所属的类,来区分同名函数属属于哪一个类的
主函数
步骤
定义对象
单对象
同一个类的所有对象共享同一组类方法
每种方法只有一个副本
对象占用不同的内存块。但函数使用的只有一个副本
只读对象
正确写法
函数不会修改对象
而非
初始化对象
构造函数法
用动态内存new
默认法
不写初始化内容时,自动调用默认法
调用默认部分
也可以用大括号来进行初始化
赋值
初始化可能会创建临时对象
赋值则是右值变成常量,然后创建临时变量将该常量赋值给stock1,随后自动删除临时变量
析构函数
在函数自身生命周期结束后会自动调用析构函数
为了便于观察,main多了一个大括号
在函数结束时自动调用析构函数来清除动态变量
对象数组
定义与初始化
对象的指针
this指针专门指向对象
使用this指针
类的声明与定义
函数原型
函数定义
提供方案
this指的是调用该函数的对象
主函数
将this指针指向stock2对象
类的使用
运算符重载
格式
友元函数格式
成员函数格式
成员函数与友元函数关联与区别
关联
都能使用类的私有成员
区别
成员函数
只能使用自己类的私有成员
有this指针
友元函数
既能间接性将私有成员共享,且不需要把私有成员设置成public
无this指针,无法被继承
类型
二元运算符重载
区分
形参
调用者类型
选择运算符
不可重载的运算符
可重载的运算符
格式
1.h
声明
成员函数格式
二元表达式返回time;参数为const time &t
友元函数格式
friend
只用在声明时写
要将调用者写出来
返回值
根据表达式结果写返回值
可以实现连续调用
2.cpp
定义
成员函数格式
将调用者与形参相加
minutes和hours是调用者的
返回一个time对象
友元函数格式
不用写所属类
若调用者不是类的对象;且定义中又不需要使用私有成员
可以不使用友元函数
直接访问的对象本体
包括参数的成员也不需要访问时
main
成员函数格式
单调用
加法左比是调用者,是time类的
加法右边是对应的参数
连续调用
根据返回值来判断(从右往左)
友元函数格式
一元运算符重载
声明与定义
插入运算符重载
cout<<对象<<对象。。。。
成员函数法
连续输出
由于cout的特殊性
要保证返回值也是ostream类
类的转换
自动转换(隐式转换)
遇到常量产生的自动转换
右值;形参与实参
自动转换方法
其他类型常量转类
单形参构造函数法
类型
单参数
多参数默认参数
特殊
二义性
double,int,long单形参不要同时存在
常量形参也会调用自动转换构造函数
对象变量=其他类型常量
类常量转其他类型
转换函数法
operator
声明
转换函数
定义
使用
其他类型常量=对象变量
取消自动转换
explicit
强制转换
使用强制类型转换可避免二义性
其他转成类
类转成其他
应指明类型型避免二义性
转换二义性
同时存在自动转换和强制转换
无法判断转换ius还是20.2
类与动态分配
私有成员
类静态
静态成员初始化
整个类只使用一个静态成员副本
静态成员函数
静态成员函数只能访问静态成员,不能访问成员(因为不与对象绑定)
格式
声明+定义
使用
const成员
初始化
在构造函数初始化列表中初始化
在声明中初始化
不可被赋值
指针类成员
必须初始化
公有
类默认的函数
默认复制构造函数
执行方式
逐个复制非静态成员的值给临时副本
若成员中包含对象,则使用该类的复制构造函数还复制成员对象
析构函数
不能删除动态内存
赋值运算符
默认成员按值赋值
与默认复制构造函数类似的问题,只不过是出现在赋值部分
knot和headline1的指针成员指向了同一个内存
knot生命周期结束时析构该指针成员指向的内容;headline1结束时再次调用析构导致该内存被二次删除形成错误
默认地址运算符&
返回使用&的对象的地址
存在指针指向动态内存时必须具备
复制构造函数
调用时机
对象出现副本时调用
对象初始化时=另一对象
另一对象为常量调用复制构造函数创造副本
按值传参
返回值为值
格式
若使用默认复制构造函数
赋值构造函数
若使用默认,则在副本结束后被析构,析构函数会删除指针指向的动态内存的内容
析构函数
delete
delete[]
赋值构造函数
使用时机
对象赋值对象时使用
格式
先析构旧内存
返回对象的引用
可以连续赋值
若使用默认赋值构造函数
knot和headline1的指针成员指向了同一个内存
knot生命周期结束时析构该指针成员指向的内容;headline1结束时再次调用析构导致该内存被二次删除形成错误
返回对象
类型
返回对象的引用
优先选引用
返回const对象引用
常量引用
绑定到临时变量上
返回const对象
返回对象
缺点
返回对象将导致调用复制构造函数
返回对象效率很低
使用
用于返回函数内局部对象
返回引用函数内局部对象会出错;返回对象则是复制一个新的对象以及内容
返回重新构造不会调用析构函数析构返回的自动对象
返回函数内的自动变量会导致自动对象周期结束后调用析构,若有new直接出错
定位运算符new
同位置创建会覆盖
重叠
不重叠
定位运算符创建对象所用的析构函数
显式调用析构函数
、
构造函数
初始化列表
构造函数运行顺序
初始化列表,创建大括号内成员,执行括号内容,执行大括号内内容
友元
小的友元可以访问大的私有保护成员
友元函数
特点
友元函数可以访问被包含的私有成员
由于调用者不是类对象,所以不能在定义时使用类成员
友元函数不是成员函数,因此定义时不需要写所属
友元不能进行传递
使用场合
使用
交换其他类的私有成员,可以通过参数写类对象的方法来使用
通常友元函数参数都是类的对象
友元类
需要友元类的情况
不是is-a;has-a。而是一个类可以改变另一个类的状态
友元作用
A中有友元类B;则B可以访问A的私有成员与保护成员
步骤
两种方式
声明友元类
让Remote所有函数都能使用TV的私有成员
声明友元类的函数
让Remote特定函数使用TV的私有成员
排列顺序(三个必须这样写)
由于B中要使用A的私有和保护成员;因此B类前要先写个A类的前向声明
TV类含友元remote;函数remote;TV类含友元remote
由于A要使用B来做友元,因此类声明应该是B在A前面
共同友元
两个类使用了同一种友元函数
友元函数可用inline定义
共用同一副本(因为友元不是某个类的)
此时可同步probe和analyzer中友元函数