C++基础知识整理from hm

1、变量存在的意义:方便我们管理内存空间;
数据类型存在的意义:给变量分配合适的内存空间
在这里插入图片描述
注:要是没这个-0(1 000 0000 0000 0000)那么表示的范围刚好是[-2^15-1, -2^15-2, -2^15-3…, -3, -2, -1, 0, 1, 2, 3, …, 2^15-3, 2^15-2, 2^15-1],但是这个-0就很难受,那1+(-1)到底是等于+0还是-0?于是计算机底层在用补码存储数据的时候,规定这个-0(1 000 0000 0000 0000)就取它字面上的值,1 000 0000 0000 0000要是个无符号整型数据表示的就是215,但是又规定把它划到负数那边,于是负数就多了一个(-215)。也就是说,这个-2^15(1 000 0000 0000 0000)的负号,是计算机规定的,不是这个字面上的二进制数表示出来的,这个数从字面上看,他要是有符号,应该是-0,要是无符号,应该是215,怎么也不能-215,这是规定的!
2、常量定义的两种方式:#define 宏常量 值;const 类型 常量;
3、标识符只能由字母、数字、下划线组成(第一个字符可以为字母或者下划线)
4、sizeof统计数据类型所占的内存大小(占得字节数)
5、浮点型(默认情况显示6位有效数字,从第一位算起)
在这里插入图片描述
float f1 = 3.14f;这里不加f编译器会把它当成双精度,多做一步类型转化
科学计数法:3e(+/-)2,这里可以填正号或者负号
6、字符型(占一个字节)
字符型变量不是把字符本身放到内存中存储,而是将对应的ASCII编码放到存储单元中
7、常见转义字符(\n,\,\t–水平制表符有对齐的效果(默认补充8个位置))
8、字符串型
C风格字符串:char 变量名[] = “字符串”
C++风格:string 变量名
9、bool类型
true/false
10、数据的输入(从键盘)
int a;
cin>>a;
11、运算符类型:算术运算符、赋值运算符、比较运算符、逻辑运算符(这四个是基本)
算术运算符:
在这里插入图片描述
C++和C中两个整数相除仍然是一个整数
赋值运算符:
在这里插入图片描述
比较运算符:
在这里插入图片描述
逻辑运算符:
在这里插入图片描述
三目运算符:表达式1?表达式2:表达式3-------既可以作为左值,也可以作为右值
12、C++三种程序运行结构:顺序结构、选择结构、循环结构
switch(表达式){ // 只能是整型或者字符型
case 1:
执行语句;
break;
default:
执行语句:
break;
}
先执行一次循环体
do{

}while();
13、系统生成随机数:rand()–生成的是伪随机数,第一次生成后就固定了、srand((unsiged int)time(NULL))—随机数种子,利用当前系统时间生成随机数,防止每次随机数都一样;
14、数组
int a[2];
int a[2] = {1, 2};
int a[] = {1, 2};
对于一维数组名a,sizeof(a) = 8,arr本身为16进制,为这个数组的首地址,也为数组中第一个元素的地址;
数组名是常量,不可以进行赋值操作

二维数组定义方式:
int a[2][2],里面元素默认是一个很大的值
int a[2][2] = {{1, 2},{1, 2}}
int a[2][2] = {1, 2, 1, 2} 会自动分成两个小数组
int a[][2] = {1,2,3,4} 自动每个行分两个元素
对于二维数组名,可查看数组所占内存空间,获取二维数组首地址(第一个元素,第一行,整个数组的地址)

15、函数:将一段经常使用的代码封装起来,减少重复代码
值传递:形参不影响实参
常见样式:无(有)参数无(有)返回值
函数声明:告诉编辑器名称以及如何调用这个函数,函数实际主体可以单独定义
函数可以声明多次,定义只能有一次;
功能函数的定义如果在main函数之后,main函数前要有功能函数的声明;
16、指针:间接访问内存(指针就是一个地址)–不管什么类型的指针,默认占用内存:在32位操作系统(x86)4个字节,在64位操作系统(x64)占用8个字节
int* p = &a;
空指针:指针变量指向内存中编号为0的空间(空指针是不可以访问的–0-255之间的内存编号是系统占用的,因此不可以访问)
野指针:指向非法的内存空间(不可以访问)
常量指针:const int* p = &a–指针的指向可以修改,但是指针指向的值不可以修改
指针常量:int* const p = &a–指针的指向不可以修改,但是指针指向的值可以修改
地址传递:swap(&a, &b); swap(int*, int*);
17、结构体:属于用户自定义的数据类型,允许用户存储不同的数据类型
struct Stu{
string name;
int age;
}s3;这里可以顺便创建一个结构体变量(也可以不要s3);
(struct) Stu s1;(定义变量这里的struct可写可不写)
struct Stu s2 = {“w”, 18};

结构体数组:
struct Stu sArr[2] = {
{“w”, 18},
{“L”, 18},
};

结构体指针:
struct Stu* p = &s;

结构体嵌套结构体:
struct tea{
string name;
int age;
struct Stu st;
};

结构体作为函数参数:
值传递:
printS(struct Stu s);
地址传递:
printS(struct Stu* p);
18、C++程序执行时,内存 大方向 划分4个区域:
程序运行前:
代码区:存放函数体的二进制代码,由操作系统进行管理
存放CPU执行的机器指令
代码区是共享的,对于被频繁执行的程序,只需要在内存中有一份代码即可
代码区是只读的,防止程序意外修改它的指令;
全局区:存放常量(字符串常量–“hello”,const全局常量)、全局变量、静态变量
该区域数据在程序结束后由操作系统释放
程序运行后:
栈区:由编译器自动分配释放,存放函数的参数值、局部变量、还有局部常量;–不要返回栈区局部变量的地址(第一次可以打印正确的*p,是因为编译器做了保留,第二次打印这个数据不再保留)–也不要返回局部变量引用

堆区:由程序员分配释放,若程序员不释放,程序结束时由操作系统回收(C++利用new开辟堆内存)--可以返回堆区变量地址
int* p = new int(10);指针本身也是局部变量,放在栈上,指针保存的数据在堆区

19、new运算符
堆区创建数据
返回该数据类型的指针
delete p–释放堆区,p应该置为空
new开辟堆区数组
int* arr = new int[2];
delete[] arr;
20、引用:给变量起别名
引用必须初始化,引用不可以更改
如果函数的返回值是引用,这个函数调用可以作为左值
*引用的本质在C++内部实现是一个指针常量:
int a = 10;
int& ref = a;在编译器相当于int
const ref = &a;
ref = 20;ref会被编译器解释成*ref = 20;
常量引用:主要用来修饰形参,防止误操作–在函数形参列表中,可以加const修饰形参,防止形参改变实参
引用必须引用一块合法的内存空间,但是下面除外:
cosnt int& ref = 10;加了const后,编译器将代码修改 为 int temp = 10; const int& ref = temp;
21、如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都必须有默认值
如果函数的声明有默认参数,函数实现就不能有默认参数(声明和实现只能有一个有默认参数)
函数的 占位参数(也可以有默认参数):
void fun(int a, int = 10){} ----这里的写法注意int = 10

22、函数重载:函数名可以相同,提高复用性(函数参数类型不同(const也是不同),个数不同,顺序不同),和函数返回值无关
注意事项:引用作为重载条件;
有默认参数的函数重载
二十三、类和对象
三大特性:封装继承多态
封装:1、将属性和行为作为一个整体表现生活中的事物
2、将属性和行为加以权限控制
C++中struct和class唯一的区别:默认的访问权限(前者public,后者private)
成员属性常设置为私有的原因:可以自己控制读写权限;对于写权限,我们可以检测数据的有效性
(一)、构造函数
1、如果我们不提供构造函数和析构函数,编译器会提供,但是是空实现
constructor(){}
没有返回值也不写void
函数名称与类名相同
可以有参数,因此可以重载
程序在调用对象的时候会自动调用构造,无需手动调用,而且只调用一次
~destructor(){}
没有返回值也不写void
函数名称与类名相同,前面加~
不可以有参数,因此不可以重载
程序在对象销毁前会自动调用析构,无需手动调用而且只会调用一次
2、构造函数的分类以及调用:
按参数分类:
无参构造:
调用:A a;—注意:调用默认构造函数也不加小括号,加了会不创建对象(A a();编译器会认为是一个函数的声明,不会认为是在创建对象)
有参构造:
调用:B b(1); 括号法
按类型分类:
普通构造:
拷贝构造:
Person(const Person &A){
}
调用:C c(a); 括号法
显示调用法:Person p2 = Person(10); 有参构造
Person p3 = Person(p2); 拷贝构造
匿名对象:Person(10);当前行(注意当前行)执行结束后,系统会立即回收匿名对象
Person(p3);不要利用拷贝构造函数初始化匿名对象,编译器会认为它等价于Person p3,是一个对象的声明,如果前面已经有p3,会导致重定义;
隐式转换调用法:
Person p4 = 10;相当于Person p4 = Person(10); 有参构造
Person p5 = p4;拷贝构造
3、拷贝构造函数的调用时机
使用一个已经创建完毕的对象来初始化一个新对象;
值传递方式给函数参数传值:
void doWork(Person p){}
void test02(){
Person p;
doWork(p);–p传给形参就调用了拷贝构造函数
}
以值方式返回局部对象
Person doWork2(){
Person p1;
return p1; —值返回,这里拷贝一个新的p1出来;
}
void test03(){Person p = doWork2();}
4、构造函数调用规则
默认情况下,C++编译器至少给一个类添加三个函数
1、默认构造函数(无参,函数体为空)
2、默认析构函数(无参,函数体为空)—堆区的代码常在这里做析构操作
3、默认拷贝构造函数,对属性进行值拷贝
4、赋值运算符operator=对属性就行值拷贝
但是,如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造
如果用户定义拷贝构造函数,C++不会再提供其他构造函数
5、深拷贝和浅拷贝
浅拷贝:简单的赋值拷贝操作—可能导致堆区的内容重复释放
深拷贝:在堆区重新申请空间,进行拷贝操作
Person(const Person& p){
m_age = p.m_age;
//m_height = p.m_height //浅拷贝,等号赋值操作
m_height = new int(*p.m_height); //重新new一块堆内存解决浅拷贝问题;
}
~Person(){
//当堆区有空间需要释放,需要在析构函数中释放干净
if(m_height != NULL){
delete m_height; //释放堆空间
m_height = NULL; // 指针置为空
}
}
6、初始化列表
7、类对象作为类成员(对象成员):C++类中的成员可以是另一个类的对象
class Phone{
public:
Phone(string pName){
m_PName = pName;
}
string m_PName;
}
class Person{
public:
//这里的m_Phone(pName)相当于 Phone m_Phone = pName 隐式初始化
Person(string name, string pName):m_Name(name), m_Phone(pName){
}
string m_Name;
Phone m_Phone;
}
运行程序可以看到:Phone的对象先构造,Person的对象后构造----即当其他类作为本类的成员,构造时候先构造类对象成员,再构造自身;而析构顺序和构造顺序相反,先析构自身,再析构类对象成员
8、静态成员函数
所有对象共享一个静态成员函数(所以不需要创建对象也可以直接访问,Person::func())
静态成员函数只能访问静态成员变量(因为非静态成员变量特定属于某一个对象,直接调用分不清是哪一个对象的)
调用方式:通过对象访问
Person p;
p.func();
通过类名访问
Person::func();
注意:静态成员函数也是有访问权限的,类外访问不到私有静态成员函数
9、C++对象模型和this指针
成员变量和成员函数是分开存储的
class Person{
};
Person p;那么sizeof(p)= 1,因为C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置,每个空对象也应该有独一无二的内存地址
class Person{
int m_a;
static int m_b; //静态成员变量不是对象所独有,不属于类的对象上
void func(){}; // 非静态成员函数,也不属于类的对象上
static void func2(){}; // 静态成员函数,也不属于类的对象上
};
Person p;那么sizeof(p)= 4;总结:只有非静态成员变量属于类的对象上

每一个非静态成员函数只会诞生一份函数实例,也就是多个同类型的对象会共用一块代码
this指针:指向被调用的成员函数所属的对象,不需要定义直接使用即可–本质是指针常量,指针的指向是不可以修改的
用途:当形参和成员变量同名时,可以用this指针来区别
在类的非静态成员函数中返回对象本身,可使用return *this;
Person& PAA(Person& p){ //这里返回引用,因栈内存结束即释放
this->age += p.age;
return *this;
}

空指针访问成员函数:
class Person{
void show(){
if(this == NULL) return;//防止空指针做一个校验
cout<<(this->)m_age<<endl;//这里会报错,因为传入的指针是NULL,不指向某个具体的对象,不能调用成员变量
}
int m_age;
};
Person *p = NULL;p->show();

const修饰成员函数(本质是修饰this指针,即指针指向的对象不可以修改):
void show() const{
this->m_B = 100;加了mutable,可以修改
this->m_a = 100; //成员函数后加了const,修饰this的指向,this指向的值不可以修改
}
int m_A;
mutable int m_B; //加了mutable后在常函数中也可以修改
const修饰对象:
常对象:cosnt Person p;//表明不允许修改对象的属性(mutable修饰的除外)
常对象只能调用常函数。不可以调用非const成员函数,因为可以修改属性
10、友元(可以访问类的私有成员)
全局函数做友元(friend void goodGay(Building *building);声明在类顶部即可);
类做友元:让一个类可以访问另一个类中的私有成员;(friend class goodGay;);
成员函数做友元:friend void GoodGay::visit();
二十四、C++运算符重载
运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型(自定义数据类型)
即:对于内置的数据类型,编译器知道如何进行运算,但是对于自定义的不可以
Person PAddP(Person& p);但是编译器提供一个通用的名称 Person operater+ (Person& p)
Person p3 = p1.operater+(p2) 就可以被简化成 Person p3 = p1 + p2;
成员函数重载+:Person p3 = p1.operater+(p2)是编译器的本质调用
Person operator+(Person& p){
Person temp;
temp.m_A = this->m_A + p.m_A;
return temp;
}
全局函数重载+:Person p3 = operater+(p1,p2)是编译器的本质调用
Person operator+(Person& p1,Person& p2){
Person temp;
temp.m_A = p1.m_A + p2.m_A;
return temp;
}
运算符重载也可以发生函数重载;Person operator+(Person& p1,int num)
注意:对于内置的数据类型的表达式的运算符是不可以改变的(意思是1+1不能等于0)

运算符重载左移运算符<<:
不能利用成员函数重载<<运算符,因为无法实现cout在左侧,因此只能利用全局函数重载左移运算符
cout数据类型:属于ostream输出流类,cout是标准的输出流对象,
ostream& operator<<(ostream& cout,Person& p){}
左移运算符配合友元可以输出自定义的数据类型

递增运算符重载++:
重载前缀++运算符,返回引用为了一直对一个数进行递增操作 ++a
MyInteger& operator++(){
m_Num++;
return *this;
}
重载后缀++运算符,这里int代表占位参数,可以用于区分前置和后置递增 a++
MyInteger operator++(int){ // 这里不能返回引用,因为这里temp是局部变量,函数结束栈区就释放了
MyInteger temp = *this;
m_Num++;
return temp;
}
赋值运算符重载=:
Person& operator=(Person& p){
if(m_Age != NULL){
delete m_Age;
m_Age = NULL;
}
m_Age = new int(*p.m_Age);
return *this;
}
Person p;p = p1 = p2;
关系运算符重载:让两个自定义类型对象进行对比操作 、!=、>、<,
bool operator
(Person& p){
if(this->m_Name == p.m_Name){
return true;
}
return false;
}
函数调用运算符重载():由于重载后使用的方式非常像函数的调用,因此称为仿函数(没有固定写法非常灵活)–STL中用的比较多
class MyPrint{
void operator()(string test){
cout<<test<<endl;
}
string test;
}
MyPrint print;
print(“hello”);—类似于函数调用
也可以使用 匿名函数对象 调用:MyPrint()(“print”);
二十五、继承
class 子类:继承方式 父类
公共继承:
保护继承:
私有继承:

继承中的对象模型:
	class A{
	public:
		int m_A;
	protected:
		int m_B;
	private:
		int m_C;
	}
	class B: public A{
	public:
		int m_D;
	}
	sizeof(B) = 16 因为父类中所有非静态成员属性都会被子类继承下去,且父类中私有成员属性是被编译器给隐藏了,因此访问不到,但确实被继承下去了
继承中构造和析构的顺序:
	先构造父类,再构造子类;
	析构和构造顺序相反,先析构儿子,再析构父亲

继承中同名成员的处理:
子类的对象Son s;访问子类成员属性s.m_A;访问父类成员属性s.Base::m_A;
访问子类成员方法s.func();访问父类的成员属性s.Base::func();
如果子类中出现了同名函数,则会隐藏父类中所有的同名函数(包括重载函数,只要同名),如果要访问父类中的同名函数,必须加父类作用域
继承中同名静态成员访问方式:和非静态同名函数一样(特别地,Son::Base::m_A,通过类名方式访问,访问父类作用域下)
菱形继承(钻石继承):
动物:羊、驼:草泥马
问题:m_Age存在两份,浪费资源
解决方法:利用虚继承解决
vbptr(虚 基类 指针)—指向vbtable虚基类表
class animal{}
class yang:virtual public animal{}
class tuo:virtual public animal{}
class cnm:public yang,public tuo{}
多态:
静态多态:函数重载和运算符重载属于静态多态,复用函数名----函数地址早绑定,编译阶段确定函数地址
动态多态:派生类和虚函数实现运行时多态----函数地址晚绑定,运行阶段确定函数地址
使用方法:父类的指针或引用指向子类对象
重写:函数返回值类型,函数名,参数列表完全相同
动态多态原理:
在这里插入图片描述
开闭原则:对扩展进行开发,对修改进行关闭
多态优势:组织结构清晰、可读性强、前期和后期的维护性

纯虚函数和抽象类
当类中有了纯虚函数(virtual int get()= 0),这个类也叫抽象类
抽象类是无法实例化的;
抽象类的子类,必须要重写父类中的纯虚函数,否则也属于抽象类,也就无法实例化对象

C++中的文件操作
程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
因此通过文件可以将数据持久化
C++中需包含头文件#include
文件类型分为:
1、文本文件:文件以文本的ASCII码形式存储在计算机中
2、二进制文件:文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂他们
操作文件的三大类:
1、ofstream:输出,即写操作
ofstream ofs;
ofs.open(“文件路径”, 打开方式);
ofs<<“写入数据”;
ofs.close();
打开方式:ios::in–为读文件而打开文件
ios::out–为写文件而打开文件
ios::trunc–文件存在先删除再创建
ios::app–追加方式写文件
ios::binary–二进制方式
多种打开方式配合使用|:ios::binary | ios::out–二进制方式写文件(ofs.write((const char )&p, sizeof(Person)));
二进制方式读文件:ifs.read((char
)&p, sizeof(Person));
2、ifstream:输入,即读操作
利用ifs.is_open()判断是否打开成功
四种方式读取:
char buf[1024] = {0};
while(ifs >> buf){
cout<<buf<<endl;
}
while(ifs.getline(buf, sizeof(buf))){
cout<<buf<<endl;
}
string buf;
while(getline(ifs, buf)){
cout<<buf<<endl;
}
char c;
while((c = ifs.get()) != EOF){ // EOF:end of file
cout<<c;
}
3、fstream:读+写操作

二十六、泛型编程
	模板不可以直接使用,它只是一个框架
	模板的通用并不是万能的,有些特定数据类型,需要用具体化的方式做特殊实现
	提高复用性,将类型参数化
	C++两种模板机制:函数模板和类模板
函数模板:建立一个通用函数,其函数返回类型和形参类型可以不具体制定,用一个虚拟的类型来代表
语法:
	template<typename T>
	函数声明或定义
	template--声明创建模板
	typename--表明其后面的符号是一种数据类型,可以用class代替
	T--通用数据类型,名称可以替换,通常为大写字母
	两种方式使用模板:
		自动类型推导:
			mySwap(a,b);
			注意:自动类型推导,必须推导出一致的数据类型T,才可以使用
		显示指定类型:
			mySwap<int>(a, b);
			模板必须要确定出T的数据类型,才可以使用:
				template<class T>
				void func(){}
				func<int>(); --这里必须确定类型<int>
	普通函数与函数模板的区别:
		普通函数调用时可以发生自动类型转换(隐式类型转换)
		函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
		如果利用显示指定类型的方式,可以发生隐式类型转换
	普通函数与函数模板的调用规则:
		1、如果函数模板和普通函数都可以调用(同名),优先调用普通函数
		2、可以通过空模板参数列表来强制调用函数模板
			myPrint<>(a, b);
		3、函数模板也可以发生重载
		4、如果函数模板可以产生更好的匹配,优先调用函数模板
类模板:建立一个通用的类,类中的成员数据类型可以不具体制定,用一个虚拟的类型来代表
	语法:template<typename T>
				类
	template<class NameType, class AgeType>
	class Person{
	public:
		Person(NameType name, AgeType age){
			this->m_Name = name;
			this->m_Age = age;
		}
		NameType m_Name;
		AgeType m_Age;
	}
	Person<string, int> p1("孙悟空", 999);
	类模板没有自动类型推导的使用方式
	类模板在模板参数列表中可以有默认参数
		template<class NameType, class AgeType  = int>
		Person<string> p1("孙悟空", 999);
	类模板中成员函数在调用时才去创建
类模板对象做函数参数
	1、指定传入类型
		void printPerson1(Person<string, int>& p);这里指定
		Person<string, int> p("孙悟空", 100);
		printPerson1(p);
	2、参数模板化
		template<class T1, class T2>
		void printPerson1(Person<T1, T2>& p);这里指定
		Person<string, int> p("孙悟空", 100);
		printPerson1(p);
		看一个数据的类型:typeid(T1).name()
	3、整个类模板化
		template<class T>
		void printPerson1(T& p);这里指定
		Person<string, int> p("孙悟空", 100);
		printPerson1(p);
类模板与继承
	如果父类是类模板,子类在继承的时候需要指定父类中T的数据类型
	1、明确写出父类类型
		template<class T>
		class Base{
			T m;
		};
		class Son:public Base<int>{
		}
	2、子类也模板化
		template<class T1, class T2>
		class Son2:public Base<T2>{
			T1 obj;
		}
类模板成员函数类外实现
	构造函数类外实现:
		template<class T1, class T2>
		Person<T1, T2>::Person(T1 name, T2 age){}
	成员函数类外实现:
		template<class T1, class T2>
		void Person<T1, T2>::showPerson(){}
类模板分文件编写
	问题:类模板中成员函数创建时机在调用阶段,导致份文件编写时链接不到
	解决方式:1、直接包含.cpp源文件 #include<.cpp>
					  2、将声明和实现写到同一文件中,并更改后缀名为.hpp约定的名称,并不强制
类模板和友元
	全局函数类内实现--直接在类内声明定义友元即可
	全局函数类外实现-需要提前让编译器知道全局函数的存在
	// 为了全局函数类外实现,需要提前让编译器提前知道Person类的存在
	template<class T1, class T2>
	class Person;
	// 类外实现也需要让编译器提前知道这个函数的存在,定义实现写在前面
	template<class T1, class T2>
	void printPerson2(Person<T1, T2> p){
	}
	template<class T1, class T2>
	class Person{
		friend void printPerson(Person<T1, T2> p){  //全局函数类内实现
		}
		friend void printPerson2<>(Person<T1, T2> p); //全局函数类外实现,要加空模板参数列表<>
	public:
		Person(T1 name, T2 age){
			this->m_Name = name;
		}
	private:
		T1 m_Name;
		T2 m_Age;	
	}
有参构造、拷贝构造、赋值运算符调用时机:
	MyArray <int>arr1(2);
	MyArray <int>arr2(arr1);
	MyArray <int>arr3(2);
	arr3 = arr1; // 此处使用operator = 

二十七、STL
诞生原因:提高复用性,避免重复工作
STL广义上划分:容器、算法、迭代器
容器和算法之间通过迭代器进行无缝连接
STL中几乎所有的代码都采用了类模板和函数模板
STL分为六大组件:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
容器:各种数据结构,vector、list、deque、set、map等用来存放数据
序列式容器:强调值排序,序列式容器中每个元素均有固定的位置
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
算法:各种常用算法,sort、find、copy、for_each等
问题的解法,有限的步骤解决逻辑或数学上的问题
质变算法:运算过程中会改变区间内元素的内容,例如拷贝、替换、删除
非质变算法:运算过程中不会改变区间内元素内容,例如查找、技术、遍历、寻找极值
迭代器:容器和算法之间的胶合剂
提供一种方法,使之能够依序访问某个容器所含的各个元素,而又无需暴露该容器的内部表示方式
每个容器都有自己专属的迭代器
迭代器的使用类似指针
输入迭代器:对数据只读访问
输出迭代器:对数据只写访问
前向迭代器:读写,并能向前推进迭代器
双向迭代器:读写,并能向前向后推进
随机访问迭代器:读写、可以跳跃方式访问任意数据,功能最强
仿函数:行为类似函数,可以作为算法的某种策略
适配器:一种用来修饰容器或者仿函数或者迭代器接口的东西
空间配置器:负责空间的配置和管理
容器:
遍历vector输出所有值:
#include
void myPrint(int val){
cout<<val<<endl;
}
for_each(v.begin(), v.end(), myPrint);
vector存放自定义数据类型并打印
class Person{
public:
Person(string name, int age){
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
存放自定义数据类型:
vector v;
Person p1(“w”, 18);
v.push_back(p1);
存放自定义数据类型的指针:
vector<Person*> v;
v.push_back(&p1);
string:C++风格字符串,本质上是一个类,类内部封装了char*,管理这个字符串,是一个char型的容器
内部构造函数:string(), string(const char
s), string(const string& str),string(int n, char c);
str.assign(“hello”, 2); 赋值"he"
string& append(const char* s, int n); 拼接s的前n个字符
string& append(const string& s, int pos, int n); 拼接s的从pos开始的前n个字符
int pos = str.find(sttr),没有返回-1,否则返回位置下标,从左往右找
int pos = str.rfind(sttr),rfind从右往左查找
str.replace(pos, n, “ss”),从pos开始的n个字符替换为ss
str1.compare(str2),如果返回0,说明等于,返回1,说明1大于2,返回-1,说明1小于2
str.at(pos) = ‘x’,通过at不仅可以读取也可以修改
str.insert(pos, “ss”),在pos位置插入ss
str.erase(pos, n);从pos起删除n个字符
str.substr(pos, n),从pos起的n个字符
vector:和数组相似,也叫单端数组,数组是静态空间,但是vector可以 动态扩展(并不是在原空间后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间)–vector内是随机迭代器
v1.assign(v2.begin(), v2.end());
v.capacity()获取容器的容量
v.resize(n, num);变长就用num代替,num可以省略(变长就用0填充),缩短就删除

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值