第一次写博客,决定把自己写的课程笔记全部上传一下,方便后来人学习~ o(* ̄▽ ̄*)o
从自学转码上岸到现在快两年了,收集了很多语言和编程思路方面的重难点,供参考
目录
声明:b是a的引用,int &b = a;(注:引用的同时必须初始化,且不能修改引用的对象)
作用:传递函数参数;仅cpp可用,修改了地址所指向的原内存的值
继承:派生类(子类)继承基类(父类)的成员,同时还可以定义自己的成员。
派生类继承方式:①公有继承public ②私有继承private ③保护继承protected
派生类成员访问权限:①不可访问的成员 ②公有成员 ③私有成员 ④保护成员
同名覆盖原则:优先使用派生类中同名成员,若要使用基类中同名成员,调用前加 基类::
多继承:一个派生类有多个基类(单继承:一个派生类有一个基类)
带默认形参的函数:cpp允许函数声明时给出形参默认值;要求按从右向左顺序;
c标准库:C 运行时库参考 | Microsoft Learn
cpp标准库:C++ 标准库参考 | Microsoft Learn
字符串流:系统头文件<sstream>(基于string类)、<strstream>(基于char *类)
异常:管理错误的特殊对象,若处理则会继续运行程序,若未处理则会终止程序并回溯报告。
①申请空间:p=new 数据类型/数据类型[元素个数n]; ②归还空间:delete p/[] p;
2、类和对象:
class 类 {
访问范围说明符private/public/protected:
成员变量/函数;
} ;
(注:类的定义要在函数体外,末尾要加 ; )
根据类创建实例:类 实例(参数表)
访问实例属性:实例.属性
调用类的方法:实例.方法()
(注:①访问范围不说明,默认私有成员;私有成员的访问权限
仅限于声明它们的类的成员函数和友元函数,即使是通过引用传递的实例
②成员变量定义时不能初始化,否则不符合面向对象的意义;
const 成员变量/基类构造函数带参数/成员类构造函数带参数,
只能通过 构造函数列表 的方式进行初始化
②静态成员变量,生存期全局,作用域所有类共享;
非const静态成员定义在类内,初始化要在类外实现;可以被所有函数访问;
可以通过类名来调用,调用前加 类::
③非静态成员函数只能通过对象来调用
④静态成员函数生存期全局,作用域在类命名空间下;
不能为const;只能访问这个类的静态成员变量;
可以通过类名来调用,调用前加 类::
)
类(参数表) {函数体}
(没有返回值;未定义会自动生成一个默认构造函数和一个拷贝构造函数)
注:函数后写 :成员变量(参数),成员变量(参数) ,函数体不写,进行成员变量初始化
注:构造函数前加 explicit 关键字:
1、指定构造函数或转换函数(C++11起)为显式,即它不能用于隐式类型转换和复制初始化
2、可与常量表达式一同使用. 函数若且唯若该常量表达式求值为 true 才为显式. (C++20起)
(参数表为空,没有返回值;只能有一个,不可以重载;未定义会自动生成一个析构函数)
~类() {函数体}
· 声明:friend 数据类型 函数名(参数表);
· 定义:数据类型 函数名(参数表) {}
(注:友元函数声明放在类的内部,定义放在类的外部;
如果在友元函数中出现多个类的互相引用,可以在类定义之前,进行前向声明)
注:常对象必须绑定常引用、常指针、常成员函数;
通过常对象,只能调用它的常成员函数,或者构造函数;
常成员函数,成员函数参数表后写const,函数体内不能修改成员变量;
构造函数,不能加const;不是成员函数,即普通函数/友元函数,也不能加const
· 非const引用不能绑定临时变量,只能绑定已经存在的变量;但const引用可以
· const引用,将在必要时生成临时变量:①实参是同类型字面量②实参发生类型转换
· 能用const的地方就用const
声明:b是a的引用,int &b = a;(注:引用的同时必须初始化,且不能修改引用的对象)
作用:传递函数参数;仅cpp可用,修改了地址所指向的原内存的值
函数参数传递方式:C语言中函数参数传递三种方式_CSDN博客_函数参数传递的三种方式
①值传递(修改了复制的新内存的值)
②地址传递(修改了地址所指向的原内存的值)
③引用传递(仅cpp可用,同地址传递)
4、继承:
继承:派生类(子类)继承基类(父类)的成员,同时还可以定义自己的成员。
创建派生类时,基类必须包含在当前文件中,且位于派生类的前面。
创建组合类时,成员类必须包含在当前文件中,且位于组合类的前面。
class 派生类名:继承方式1 基类名1,继承方式2 基类名2,...
{
访问范围说明符private/public/protected:
成员变量/函数;
};
派生类构成:①从基类继承来的 ②由派生类自己定义的
派生类继承方式:①公有继承public ②私有继承private ③保护继承protected
注:public不改变,private私有化,protected保护化
派生类成员访问权限:①不可访问的成员 ②公有成员 ③私有成员 ④保护成员
注:派生类(组合类)可以通过基类(成员类)的公有成员函数来实现对其私有成员的操作
同名覆盖原则:优先使用派生类中同名成员,若要使用基类中同名成员,调用前加 基类::
认为基类能完成的任务,派生类也能完成,所以可以用公有派生类对象去代替基类对象
· 派生类对象的生成过程:
构造先基类(在多继承中,先虚拟继承、后一般继承)、后派生类的成员对象、最后派生类;
析构先派生类、后派生类的成员对象、最后基类(在多继承中,先虚拟继承、后一般继承)
· 派生类的构造函数传参数:
若 基类构造函数 或 成员类构造函数 带参数;
则 派生类构造函数 必须给 基类构造函数 和 成员类对象 传参数
多继承:一个派生类有多个基类(单继承:一个派生类有一个基类)
· 声明:class 派生类名:virtual 继承方式 基类名 {...};
· 作用:解决多继承中的菱形继承问题,防止派生类重复继承共同基类的成员。
· 位置:发生在派生类对共同基类的继承声明处。
通过在派生类对共同基类的继承声明中添加 virtual 关键字,
使得这些共同基类在派生类中只有一份实例,解决了资源浪费和二义性的问题。
注:运算符重载,若左操作数不是类的对象,
要用友元函数传2个参数,而非成员函数传1个参数
注:单目运算符,前置参数表为空,返回值是自己;后置参数表为int,返回值是临时变量
注:输出运算符 << 应该接受一个const引用作为其第二个参数,否则会报错;
传递输入输出流对象istream、ostream时,最好使用引用传递,故返回值和第一个参数要是输入输出流对象的引用,这样可以提高效率,确保状态同步,以及允许对流对象进行修改
注:若类内定义了 () 重载,则这个类的对象就是函数对象,可以当作函数使用
当对象只包含了基本数据类型成员时,可以使用浅拷贝
当对象包含了指针类型成员时,使用深拷贝
注:浅层拷贝,复制数据元素;深层拷贝,申请新空间 + 复制对象
注:浅层赋值,复制数据元素;深层赋值,当地址不同,归还原空间 + 深层拷贝
带默认形参的函数:cpp允许函数声明时给出形参默认值;要求按从右向左顺序;
若函数的声明和定义是分开的,在声明处给出默认值,在定义处不用重复给
· 定义:在基类中声明的函数,在派生类中被重新定义,以便提供对基类的多态性支持。实现在基类中定义一个通用接口,而在派生类中根据需要重新实现该接口。
· 用法:在基类的 成员函数声明前 写 virtual (派生类的同名函数自动继承为虚函数)
· 作用:动态绑定,编译器在编译时并不确定要调用的是基类还是派生类的函数,而是在运行时根据对象的实际类型进行确定,即要对该调用进行动态联编。使得在处理基类指针或引用时可以根据实际对象的类型调用正确的函数。
纯虚函数:在基类中暂时无法实现的函数,可以先声明为纯虚函数,留给派生类实现
· 用法:在基类的 成员函数声明前 写 virtual,函数体不写,赋初值为0
抽象类:有纯虚函数的类(只能作为基类;不能建立抽象类对象;构造函数不能是虚函数)
注:常将 基类的析构函数 声明成虚函数,防止析构时少释放造成内存泄漏
作用:定义抽象数据类型,编译时把数据类型参数化,一套代码适应不同数据类型
函数的定义前,要加template <class/typename 标识符>
模板的覆盖:单独写,比模板优先级更高
定义部分:
类的定义前,要加template <class/typename 标识符>
函数的实现前,要加 template <class/typename 标识符> 和 类<标识符>::
主函数:
根据类创建实例前,要加 类<数据类型>
模板类中重载<<和>>操作符 - Mr.Rico - 博客园 (cnblogs.com)
注:模板类中输入输出流运算符重载,不能使用友元函数在类内声明、在类外实现;
因为类外实现相当于重定义了一个函数模板,无法使用类的私有成员
解决方式:①在类内实现 ②通过类的公有成员函数来实现对类的私有成员的操作
模板类的友元函数分三类:
①非模板友元函数:友元函数不是模板函数,而是利用模板类参数生成的函数。
②约束模板友元函数:友元类型取决于模板类被实例化的类型,一个实例化函数模板。
·在类内对函数模板实例化声明:
③非约束模板友元函数:友元函数模板类型不同于类模板类型,一个通用型函数模板。
·声明一个与类模板类型不同的函数模板:
注:若一定会使用到模板类成员,就使用约束写法;若不一定,就使用非约束写法
注:函数的声明和实现分开,可以单独编译、保护版权
三个组件:容器(类模板)、迭代器(指针)、算法(函数模板)
· 容器(类模板):顺序容器、关联容器、容器适配器
定义容器:容器类名 变量
举例:vector<int> v(100);
注:放入容器的对象所属的类,若要使用算法,要重载 == 和 < 运算符
1、顺序容器:
2、关联容器:
3、容器适配器:
· 迭代器(指针):const迭代器、非const迭代器
定义迭代器:容器类名::iterator 变量 / 容器类名::const_iterator 变量
举例:vector<int>::iterator i;
· 算法(函数模板):修改容器算法、不修改容器算法、数字型算法
· 函数对象:若类内定义了 () 重载,则这个类的对象就是函数对象,可以当作函数使用
c标准库:C 运行时库参考 | Microsoft Learn
①系统头文件<stdio.h>→<iostream>
②系统头文件<stdlib.h>→<cstdlib>
③系统头文件<math.h>→<cmath>
④系统头文件<string.h>→<cstring>
cpp标准库:C++ 标准库参考 | Microsoft Learn
①系统头文件iomanip:
举例:控制输出小数的精度,关于C++保留几位小数输出(iomanip)
第一种: cout<<setiosflags(ios::fixed)<<setprecision(n)<<num;
这里的n就是要保留几位小数
第二种: cout<<fixed<<setprecision(n)<<num;
其实就是第一种的简写
常用的输出操纵符有:
setbase(n) 设置整数为n进制(n=8,10,16)
setfill(c) 设置字符填充,c可以是字符常量或字符变量
setprecision(n) 设置浮点数的有效数字为n位
setw(n) 设置字段宽度为n位
setiosflags(ios::fixed) 设置浮点数以固定的小数位数显示
setiosflags(ios::scientific) 设置浮点数以科学计数法表示
setiosflags(ios::left) 输出左对齐
setiosflags(ios::right) 输出右对齐
setiosflags(ios::skipws) 忽略前导空格
更完整的在这里:Input/output manipulators - cppreference.com
②系统头文件sstream(基于string类)、strstream(基于char *类):
字符串流对象:输入/输出字符串流对象 stringstream str/istringstream istr/ostringstream ostr
注:字符串流一般3个头文件和3个流对象都会用到
③系统头文件fstream:
文件流对象:输入/输出文件流对象 fstream iofile/infile/outfile
注:文件流一般只用到1个头文件,但3个流对象都会用到
①系统头文件algorithm:泛型算法
函数__gcd(int a,int b):求两个整数的最大公约数,返回值是整数
1、读容器元素算法:
2、写容器元素算法:
3、排序容器元素算法:
排序算法:sort(起始指针,结束指针,比较算法):对指定范围内的容器元素,按一定规则排序
举例:sort(v.begin(),v.end(),mycom);
其中,比较算法为bool mycom(int a,int b) { return a>b; }
②系统头文件numeric:算术算法
③系统头文件functional:函数对象
④系统头文件string:
字符串型:std::string
注:capacity() 返回的是对象分配的内存大小,
而 length() 和 size() 返回的是对象实际存储的元素个数。
⑤系统头文件vector:
动态数组型:vector<值类型>
定义动态数组对象,vector<值类型> 动态数组对象v
(定义二维动态数组对象:vector<vector<值类型>> 动态数组对象v)
注:当vector容量不够,double一下
⑥系统头文件deque:
双向队列型:deque<值类型>
定义双向队列对象,deque<值类型> 双向队列对象q
⑦系统头文件list:
双向链表型:list<值类型>
定义双向链表对象,list<值类型> 双向链表对象l
(更准确地说,是带头结点的循环双向链表)
⑧系统头文件set:
集合型:set<值类型>
定义集合对象,set<值类型> 集合对象s
⑨系统头文件map:
字典型:map<键类型,值类型>
定义字典对象,map<键类型,值类型> 字典对象dic
访问字典元素,dic[“键”]=”值”
⑩系统头文件set、map:
多重集合型:multiset<值类型>
定义多重集合对象,multiset<值类型> 多重集合对象s
多重字典型:multimap<键类型,值类型>
定义多重字典对象,multimap<键类型,值类型> 多重字典对象dic
命名空间:处理程序中常见的同名冲突
· 定义:namespace 命名空间名 {变量/函数的声明}
· 调用:命名空间名::变量/函数(可用using指令省去 命名空间名:: 前缀)
using namespace std; 允许在使用标准库组件时,不需要每次都加上 std:: 前缀
输入输出流:
输入输出流对象:
输入符号 cin(读到空白为止;最后的空白会存入缓冲区),
输出符号 cout/cerr(输出错误信息)/clog(输出日志信息)(读到0/’\0’/NULL为止)
操纵器:换行符号 ‘\n’→endl
运算符:输入运算符>>,输出运算符<<
1、输入:std::cin>>常量/变量
2、输出:std::cout/cerr/clog<<常量/变量
注:输出运算符 << 应该接受一个const引用作为其第二个参数,否则会报错;
传递输入输出流对象istream、ostream时,最好使用引用传递,故返回值和第一个参数要是输入输出流对象的引用,这样可以提高效率,确保状态同步,以及允许对流对象进行修改
字符串流:系统头文件<sstream>(基于string类)、<strstream>(基于char *类)
字符串流对象:输入/输出字符串流对象 stringstream str/istringstream istr/ostringstream ostr
stringstream类的成员函数:
①str():将stringstream对象转换为string字符串
②clear():清除流状态,可以清除流对象的错误标志和结束标志
注:stringstream对象常用于做数据类型转换,字符串类型 <=> 其他类型;
如果打算重用已存在的流对象,再次使用前记得关闭(close)和清除(clear)流对象
1、兼容c的文件操作:
文件输入/输出:
①重定向 .\文件 < a.in / > a.out
②定义FILE类型指针
FILE* fp=fopen(“文件”,“模式”);
if (fp) {
fscanf(fp,“格式控制字符串”,&输入参数一,&输入参数二);
fclose(fp,“格式控制字符串”,&输出参数一,&输出参数二);
} else {
...
}
①打开和关闭文件
·打开文件:fopen(“文件”,“模式”)
(返回FILE类型指针,若打开失败,则返回NULL)
自动创建文件,将会在执行文件所在目录。
(若要打开二进制文件,在模式后加b;例如’rb’,以只读模式打开二进制文件)
·关闭文件 fclose(fp)
相对文件路径:若在执行文件所在目录的子文件夹中,’子文件夹\文件’
绝对文件路径:可读取任何位置的文件
②输入和输出文件
·对于文本文件:
1、输入:fscanf(fp,“格式控制字符串”,&输入参数一,&输入参数二)
(返回正确读入参数的个数,当没有输入/输入参数有错,返回特殊值EOF(-1);
输入参数的默认值为0;读到空白为止;读入字符串时,
(1)每一个字符都会存在缓冲区内,包括最后的空白
(2)两次读入字符的scanf()中间要加入一个getchar()来刷新缓冲区)
(最优的清除输入缓冲区的方法,while ((ch=getchar())!='\n'&&ch!=EOF) ;
【C语言】getchar 函数的正确使用_getchar()函数具体应该怎么使用-CSDN博客)
2、输出:fprintf(fp,“格式控制字符串”,&输出参数一,&输出参数二)
(返回正确输出字符的个数,当没有输出/输出字符有错,返回特殊值EOF(-1);
读到0/’\0’/NULL为止)
·对于二进制文件:
- 输入:fread(存储数据的内存地址,每个内存所占字节数,内存个数,fp)
(返回正确读入的基本单元数,当没有输入/输入内容有错,返回特殊值EOF(-1);
输入参数的默认值为0;读到空白为止;读入字符串时,
- 每一个字符都会存在缓冲区内,包括最后的空白
(2)两次读入字符的scanf()中间要加入一个getchar()来刷新缓冲区)
(最优的清除输入缓冲区的方法,while ((ch=getchar())!='\n'&&ch!=EOF) ;
【C语言】getchar 函数的正确使用_getchar()函数具体应该怎么使用-CSDN博客)
2、输出:fwrite(存储数据的内存地址,每个内存所占字节数,内存个数,fp)
(返回正确写入的基本单元数,当没有输出/输出内容有错,返回特殊值EOF(-1);
读到0/’\0’/NULL为止)
③在文件中定位
·获取当前所在文件位置:ftell(fp)(返回当前所在文件位置)
·移动当前所在文件位置:fseek(fp,位移,起始位置)(若移动成功,返回0;失败,返回非0)
·将文件指针重新定位到文件的开头:rewind(fp);
2、c++的文件流操作:系统头文件<fstream>
文件流对象:输入/输出文件流对象 fstream iofile/infile/outfile
①打开和关闭文件
·打开文件:infile/outfile.open(“文件”,“模式”);
·关闭文件:infile/outfile.close();
②输入和输出文件
1、输入:infile.read(存储数据的内存地址,每个内存所占字节数)
(返回正确读入的基本单元数,当没有输入/输入内容有错,返回特殊值EOF(-1);
输入参数的默认值为0;读到空白为止)
2、输出:outfile.write(存储数据的内存地址,每个内存所占字节数)
(返回正确写入的基本单元数,当没有输出/输出内容有错,返回特殊值EOF(-1);
读到0/’\0’/NULL为止)
③在文件中定位
·获取当前所在文件位置:tellg/p()(返回当前所在文件位置)
·移动当前所在文件位置:seekg/p(位移,起始位置)(若移动成功,返回0;失败,返回非0)
异常:管理错误的特殊对象,若处理则会继续运行程序,若未处理则会终止程序并回溯报告。
throw 语句:
throw 变量名;
try-catch代码块:
try {可能引发错误的代码}
catch1 (数据类型 变量名) {错误时要执行的命令}
catch2 (数据类型 变量名) {错误时要执行的命令}
catch3 (...) {错误时要执行的命令}(匿名捕获异常,捕获任意类型的异常)
注:碰到抛出的异常时,先捕获异常并执行捕获语句,再执行捕获语句的后续代码
标准异常:系统头文件<exception>
注:成员函数what():返回错误消息
特殊对象指针——this指针:
注:this是当前所在对象的地址,数据类型为 类 *this
①申请空间:p=new 数据类型/数据类型[元素个数n]; ②归还空间:delete p/[] p;
注:释放指针所指向的内存,而不是删除指针变量本身
注:范围for遍历二维数组,取出的是每一行,要用多重循环
注:在使用auto关键字定义变量时,必须进行初始化,
编译器通过初始化表达式推导变量类型。若没有初始化,编译器无法确定变量的类型。