一年前的自学一知半解,本科毕设用python写的导致C++的记忆被清空了。再次学习希望可以有更多的理解,不足之处希望未来的我可以指正。
对象:理解为数据+服务。即自身的动静属性加上对外界的作用。实体
类:是一个概念,包括许多属性。非实体
分装encapsulation:隐藏数据,外界只能访问接口。
继承,多态性
在用c++时添加类,与python不同,声明放在头文件,内容放在另一个文件。
#include "TicketMachine.h" 无括号在当前目录找
#include<iostream> 有括号在系统目录找
构造函数,析构函数~没有类型
public 任何都可以访问
private 只有自己本类的成员函数可以
protect 类自己以及子类访问
class默认私有和struct默认公有,其余无差别
5.1
全局变量:各个模块通用,其他文件用extern声明
静态局部变量:生存周期长,一直存在。但是其作用域仍与局部变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。
静态全局变量:当程序只有一个文件模块,其与一般全局变量作用相同; 当程序有多个模块时,静态全局变量的作用范围局限于该模块。
5.2
静态数据成员
static声明 被该类的所有对象共享,具有静态生存期。
一般在类外初始化,用::指名所属的类,例如:
类内:
class CStudent{
private:
static int Count;//声明了Count变量但未分配内存
}
类外:
int CStudent::Count = 0;//定义静态成员变量,同时初始化为0
静态常量(const/constexpr)可以类内初始化
静态函数成员
可以直接用类名和作用域调用,处理静态成员(可以直接调用静态成员函数)
可以理解为类的功能,不需要指定的对象
函数前加static即可
friend 友元
可以是友元函数和友元类,声明后代表对方可以访问本类
5.3
常对象 不能被更新 ,只能调用常成员函数。 const 类名 a()
常成员函数 void 域名::函数名() const
常数据成员 只能通过构造函数的成员初始化列表显示进行,如Myclass::Myclass(int i,int j):x(i),a(j),r(x){}。const 类型 a
常引用 效率高又不破坏实参 const 类型 &a
六 数组指针字符串
6.1
数组 有一定顺序关系的若干相同类型变量的集合,组成数组的变量叫元素。
常数组 const 类型 a[][] 数组传参的时候传入首地址,用const可以保证原数组不变。
对象数组
数组名[下标].成员名 访问成员函数
类名 数组名[元素个数] 定义对象数组
6.2
&地址运算符 &a即为a的首地址 *指针运算符 *ptr为ptr指向的内容
指针变量
int i ;
int* ptr = &i ; ptr为int类型指针变量,只能存int型,指向i 。void类型的指针可以被赋予任何类型的地址。
static的变量也要用static指针
常指针
指向常量的指针
int a;
const int* p1 = &a; // p1是指向常量的指针
int b;
p1 = &b; //可以,p1可以指向别的
*p1 = 1; //不行,不能通过常指针改变变量
//a, b自己可以变化
指针类型的常量
int a,b;
int *const p2 = &a;
*p2 = 3; //可以,相当于给a赋值
p2 = &b //不行,指针常量不能变化
6.3
指针数组 point *pa[2] point型指针数组,存放指向point的指针
6.4
用指针作为函数参数 可以改变指针所指向的数据(引用) 或者传数组时使用(可以只传首地址)
如果传指针时不修改,则要声明const,如 void A(const int* p)
传指针和传引用的区别:https://blog.csdn.net/YL970302/article/details/86296428,通常情况下传引用比传指针更加安全
返回值是指针类型的函数 要注意
① 返回值不能是函数里定义的非静态地址
② 注意返回的地址是合法的?
函数指针 (指向程序代码储存区,主要实现函数回调)调用函数的时候更灵活,在函数里调函数
定义: 存储类型 数据类型 (*函数指针名)();
对象指针
对象指针调用成员方法 ptr->getx()
this指针 隐藏在类的非静态成员函数里
6.5
动态内存分配 new 类型名T(初始化参数) 返回特定类型的指针,用于不确定需要多大空间
例:动态分配数组,double* array = new double[n][3][4]()
释放空间
delete [] 指针p 释放p所指向的数组
delete 指针p 释放p所指向的内容
动态数组 vector容器 vector<元素类型> 数组对象名(长度)
例如: vector<int> arr(5)
封装任何类型的动态数组,可以自动创建和删除。
对象名不代表首地址,但可以用下标,size可以出尺寸
常用于储存指针,较大的类对象占用太多内存且要求有默认构造函数(看具体情况)
基于范围的for循环配合auto
auto:无类型,类型跟着右边走
七 类的继承
7.1 单继承
多继承
继承之后可以定义同名新成员,隐藏基类的成员
protect成员 继承和public一样,对象调用时和private一样
公有继承 : 基类的public和protect不变,private不可直接访问。派生类成员函数可以访问public和protect;派生类对象只能访问public。
私有继承:基类的public和protect变为private,private不可直接访问。派生类成员函数可以访问基类的public和protect;派生类的对象不能访问任何成员。
保护继承:基类的public和protect变为protect,private不可直接访问。派生类成员函数可以访问基类的public和protect;派生类的对象不能访问任何成员。
向上转型:公有派生类对象在使用上可以被当作基类的对象,反之不可。
7.2
继承时的构造函数 默认情况构造函数不被继承,派生类需要自己定义。写派生类构造函数时,只对新增成员初始化,继承的成员自动调用基类构造函数,但要给基类构造函数传参数。
可以用 using class::class强制继承基类的构造函数
单一继承时
当基类中声明有默认构造函数,派生类可以不给基类传参,也可以不声明构造函数。下图把i传给B,j初始化C
多继承情况
复制构造函数
不写派生类的复制构造函数,系统默认调用。如果写,一般要给基类传参,但只有一个参数(向上转型)。
比如C::C(const C &c1):B(c1){}
7.3
二义性 基类和派生类有同名函数,基类会被隐藏,想调用可以用类名::函数名调用。
虚基类 当继承函数出现冗余情况,一个函数被继承多次时,用虚基类的方式避免冗余和二义性。这样所有的同名函数都是用虚基类的函数成员。
class B : virtual public Base(){}
注意:虚基类之下的所有派生类,构造函数都要写给虚基类传参数。建立对象时,只有最远派生类调用虚基类的构造函数,其他基类忽略。
第八章 多态性
8.1
通过虚函数实现多态 在类定义中声明的同名函数时在前面加 virtual,实现时不用加virtual。如下图中fun函数不再被形参格式限制,而是被参数自身的类控制。(虚函数不能内联,不能是静态)
派生类的虚函数会隐藏基类同名函数的所有其他重载形式
构造函数不能是虚函数,析构函数可以
虚析构函数
下图不执行基类析构,只执行了派生类析构,这样会造成危险。所以当基类指针指向派生类对象时,需要把析构函数写成虚函数,即virtual ~Base();
抽象类 有纯虚函数的类 。 不能定义抽象类的对象
纯虚函数 在基类中没有定义具体操作内容的虚函数,要求派生类自己定义。
virtual 类型 函数名(参数)= 0;
override 显示覆盖,声明本函数必须覆盖基类虚函数。声明时 virtual void f(int) override;
final 禁止继承 class B final {};
8.2
运算符重载 可以重载为类的非静态成员函数和类外的独立函数(友元)
① 类的非静态成员函数方法
类型 operator 符号 (const 类型 &对象)const
输出自定义对象不能用cout,要重载
重载前置和后置的++ 前置重载函数没有形参,后置需要有一个int形参以作区分,但不传参
② 类外的独立函数
九 模板与群体数据
9.1
编译器根据所给数据推导出模板的具体情况
函数模板
template <class T> <>当中的叫类型参数 ,被反推出的具体类型叫类型实参
类模板
实例:
9.2
群体 :多个数据元素组成的集合体。分为线性群体和非线性群体,线性群体中元素按照位置排列,可以区分第一第二个,如数组。
线性群体 按照访问元素的方法不同分为直接访问(数组类),顺序访问(链表)和索引访问。
为什么返回引用?
如果返回值是对象的值,就是右值,不能成为左值。如果返回引用,引用是对象的别名,可以通过引用来改变对象从值,因此是左值。
如果这个类需要自己写一个深层的复制构造函数,一般也需要自己写一个重载“=”的函数
指针转换函数不写返回值类型
如下图右侧,编译器无法自动转换array<int>到int,所以需要指针转换运算符
9.3 链表类模板
链表: 链表是动态数据结构,可以用来表示顺序访问的线性群体。由系列结点组成,结点可以在运行时动态生成。
每个结点包括数据域和指向下一个结点的指针。只有指向后继节点的叫单链表
、
返回被删除的指针,因为不想它释放,直接绕过它会导致再也找不到
结点类模板实例
9.4 栈
暂略
9.5 几个简单的排序查找算法
数组元素比如某个对象中包含多个数据项,关键字比如学生对象中的学号就可以用来识别们就是关键字。
插入排序:将待排序元素按照关键字值的大小插入到适当位置,一个个比较
选择排序:每次从待排序序列中找最小的元素,把它放到末尾
交换排序:起泡排序 :每一轮通过两两比较把最大的数放到最后
二分法查找: 对于排列好的数据,每次查找中间的数,然后二分
十 泛型程序设计与STL库
10.1 泛型程序设计与STL结构
泛型程序设计:将算法从特定的数据结构中抽象出来
可比大小:重载"<",">" 静态数据不能用=赋值,不具备第三个功能
STL标准模板库
op:函数对象,inputlterator输入迭代器,outputlterator输出迭代器
使用STL函数对象,需要包含头文件<functional>
ostream_iterator<int>输出流迭代器 cout输出流对象
10.2 迭代器
迭代器可理解为抽象的指针
cin是输入流对象,与输入流迭代器关联。
第一个是关联到cin的输入流,第二个没给参数,表示指向流结束的迭代器(键盘输入结束,文件结束)。前两个合在一起是范围, 第三个是输出流迭代器
顺序容器:有逻辑上先后的容器
![](https://img-blog.csdnimg.cn/8ea7766d7be340b19f8c41936f7502ac.png)
![](https://img-blog.csdnimg.cn/e2ded9fd67a04c629d1c196c33b515a2.png)
10.3 顺序容器
q1 q2为迭代器当向量中插入新元素,后面的元素整体向后移。如果超出容量则会选择新的储存空间,之前所有的指针,迭代器和引用作废,如果未超出容量,就只有插入位置之后的指针引用迭代器作废
列表一般是为了实现链表,支持双向遍历
十一 流类库与输入输出
11.1
概念
程序将流看成文件对象的化身。读———提取,写——插入
输出流
write写二进制文件,seekp写到位置的标记,tellp写道第几个字符
setw和width只对下一次输出管用,其他操纵符大部分都管用
注意打开的文件一定要关闭
![](https://img-blog.csdnimg.cn/4fc7a8e7865d47a1b6ce30a486822cca.png)
![](https://img-blog.csdnimg.cn/11d3a1c1b5ea4aba85f05868ee335037.png)
![](https://img-blog.csdnimg.cn/bf6a6b2d90cf4b019583715ba0ee9614.png)
![](https://img-blog.csdnimg.cn/f65b3b406d104d4f94f7b875ec205c61.png)
![](https://img-blog.csdnimg.cn/6a66a8d08ffb4a23862ab691dfd1b744.png)
![](https://img-blog.csdnimg.cn/be171cba581b4ea8824925ca07ca5140.png)
![](https://img-blog.csdnimg.cn/415c19b6d2884a8a953209a48b6b4a85.png)
向二进制文件输出
write第一个参数是字符型指针,下图中为临时转换的指向起始位置,第二个是大小
向字符串输出
![](https://img-blog.csdnimg.cn/7060ca29e8fb450c8a089035633316ee.png)
11.2
输入流
不是文件结尾就一直输入
从二进制文件读取数据
payroll文件名,reinterpret_cast转换类型
seekg(3*sizeof(int)) 移动三个int的位置