C++复习-基础部分

C++复习-基础部分




一、编译,链接

1.1 预处理(Preprocessing)

  • 工作内容
    • 展开宏定义(#define指令)。
    • 处理条件编译指令(如#ifdef#ifndef#endif)。
    • 处理包含指令(#include),将被包含文件的内容插入到源文件中。
    • 删除注释。
    • 添加编译器需要的特殊标记。
  • 结果:生成一个扩展源代码文件,通常这一步骤对程序员是透明的,不产生物理的输出文件。

1.2 编译(Compilation)

  • 工作内容
    • 将预处理后的源代码转换成汇编代码。
    • 进行语法和语义分析,确保代码符合C++语言规范。
    • 优化代码,如循环优化、常量折叠等。
    • 初始化部分全局变量和静态变量
  • 结果:生成汇编语言文件,这些文件包含了可被汇编器直接翻译成机器指令的代码。

1.3 汇编(Assembly)

  • 工作内容
    • 将汇编代码转换成机器语言指令。
  • 结果:生成目标文件(Object File),这些文件包含了机器语言代码但尚未链接。

1.4 链接(Linking)

  • 工作内容
    • 解析和连接外部依赖,如库函数调用。
    • 将多个目标文件合并为一个可执行文件。
    • 处理静态和动态库的链接。
    • 分配全局和静态变量的地址。
    • 解决符号引用,即将函数调用、变量引用等与它们的定义关联起来。
  • 结果:生成最终的可执行文件或库文件。

优化

在编译和链接的过程中,编译器会进行多级优化,以提高程序的运行效率和减少程序的大小。优化的级别可以通过编译器选项进行调整。优化工作包括但不限于:

  • 编译时优化:循环展开、内联函数、死代码消除等。
  • 链接时优化(如果支持的话):进一步优化在编译阶段生成的代码,比如移除未使用的函数或变量。



二、引用

c++中引用可以当作是指针的一种包装,引用变量只能引用已有的变量且无法改变

1
2
3
4
5
6
7
8
9
10
void add(int &b){
b++;
}

int main(){
int a = 1;
add(a);
std::cout<< a << std::endl; // a=2
}




三、类与结构体的区别

  • 概念 :struct和class的语法基本相同,struct默认public,class默认private

  • 存储 :struct大部分是在程序运行中创建的,在栈上。class用new创建时在堆上

  • 关系 :在继承上struct比起class有很大的限制

  • 使用 :struct在C中不能有成员函数,C++中可以有成员函数

3.1 栈与堆

  1. 栈上
    在使用普通变量时,变量的值是保存在栈上的。

    1
    2
    3
    A obj;  // 调用默认构造函数
    A obj(1, 2); // 调用接受参数的构造函数
    A obj = A(1, 2); // 同上,但可能会涉及到拷贝或移动构造函数(编译器优化除外)
  2. 堆上
    在使用new创建对象时,对象的值是保存在堆上的。

    1
    2
    3
    A *p = new A;  // 调用默认构造函数
    A *p = new A(1, 2); // 调用接受参数的构造函数
    A *p = new A[10]; // 调用默认构造函数,创建10个对象



四、static 和 const

4.1 static

  1. 用于变量
  • 局部变量:延长生命周期到程序结束,作用域是局部的
  • 全局变量或函数:只在定义它的文件中可见
  • 类的静态成员变量:没有成员也能存在。所有该类的成员共享。但是只能在类中声明,要在类的外部进行定义
  1. 用于方法

类的静态成员函数:直接通过类名调用。静态函数只能访问和调用静态成员变量或函数。不能访问非静态成员

  1. 用于类

静态类:类的所有成员都是静态的,不能创建对象,只能通过类名访问

注:在普通函数中如果需要返回一个指针,需要:

  1. 将要返回的指针指向的东西设置为static,不然当函数结束后需要返回的空间
  2. 将要返回的指针指向的东西设置为堆中的空间,如malloc,new等

使其不在栈上,不然函数结束后会被释放

1
2
3
4
5
6
7
8
9
10
int *fun(){
static int a = 10; //没有static,函数结束后a会被释放,返回的指针指向的是一个不存在的东西
return &a;
}

int main(){
int *p = fun();
printf("%d\n", *p); // 10
}

4.2 const

  1. 用于变量
  • const修饰的变量是只读的,不能被修改
  • const修饰的变量必须初始化,在编译时分配内存,编译时就会被替换成相应的值,不会在运行时进行计算
  1. 用于方法
  • const修饰的方法不能修改成员变量,只能读取成员变量
  • const修饰的方法不能调用非const方法,因为非const方法可能会修改成员变量
  • const修饰的方法可以被const对象调用,非const对象也可以调用
  1. 用于类
  • const修饰的类对象不能调用非const方法,因为非const方法可能会修改成员变量

注:

  • 一般会在函数的参数中使用const引用(如const int &a),防止函数修改参数的值
  • 如果变量被mutable修饰,那么即使是const方法也可以修改这个变量



五、枚举

有意义的数字集合,可以通过枚举来定义。

枚举的默认值是从0开始的,可以通过赋值来改变,后面的值会根据前面的值自动递增。

类中的枚举可以通过类名::枚举内部名称来访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;

class A{
public:
enum loglevel{
INFO=0,
WARNING=2,
ERROR //3
};

private:
loglevel level;

public:
void setLevel(loglevel level){
this->level = level;
}
void printLevel(){
if(level == INFO){
std::cout<< "INFO" << std::endl;
}
else if(level == WARNING){
std::cout<< "WARNING" << std::endl;
}
else if(level == ERROR){
std::cout<< "ERROR" << std::endl;
}
}
};


int main(){
A *a = new A();
a->setLevel(A::ERROR);
a->printLevel();
}




六、类中的知识

6.1 构造函数

构造函数用于初始化对象的数据成员。名称与类名相同,没有返回值,可以有参数(一般写成参数列表),可默认。

可以有多个不同参数的构造函数,称为构造函数的重载。

1
2
3
4
5
6
7
8
9
class A{
public:
int a;
int b;

A():a(0),b(0){} // 默认构造函数
A(int a):a(a){} // 有参数的构造函数
};

注:在创建类的变量时有隐式转换,如A a = 10;会调用A(int a)构造函数,如果不想有隐式转换,可以在构造函数前加explicit

6.2 析构函数

析构函数用于释放对象占用的资源。名称与类名相同,前面加上~,没有返回值,没有参数。

析构函数在对象被销毁时自动调用,一般用于释放对象占用的资源,如释放内存、关闭文件等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A{
public:
int *p;

// 构造函数
A(){
p = new int[10]; //在堆上分配空间
}

// 析构函数
~A(){
delete[] p; //释放空间
}
};

注:new(delete)与malloc(free)的区别: new会调用构造函数,malloc不会。delete会调用析构函数,free不会

6.3 拷贝构造函数

拷贝时如果简单的赋值,如果是指针的话会出现浅拷贝,两个对象的指针指向同一个地址,一个对象释放了空间,另一个对象的指针就会指向一个不存在的地址,会出现问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

class A{
public:
int *p;

A(){
p = new int[10];
}

~A(){
delete[] p;
}
};

int main(){
A a1;
A a2 = a1; //调用拷贝构造函数
}

//这样就会在a2释放空间时出现问题,因为a1和a2的指针p指向同一个地址,a1释放了空间,a2的指针指向的是一个不存在的地址

这样就需要自定义拷贝构造函数,来解决这个问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

class A{
public:
int *p;

A(){
p = new int[10];
}

A(const A &a){ //拷贝构造函数(也能写列表参数)
p = new int[10];
memcpy(p, a.p, 10*sizeof(int)); //深拷贝
}

~A(){
delete[] p;
}
};

int main(){
A a1;
A a2 = a1; //调用拷贝构造函数
}

6.4 this指针

this指针是指向当前对象的指针,是一个隐式参数,不需要定义,可以直接使用。

在类的成员函数中,this指针指向调用该成员函数的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

class A{
public:
int a;

A(int a, int b){
this->a = a;
}

int getA() const{
const A *p = this; //this指针是指向const对象的指针
return p->a; //这里有点疑惑,只是想说明const方法中需要使用const指针
}
};


6.5 智能指针

智能指针就是对指针的封装,可以根据条件自动释放空间。

6.5.1 std::unique_ptr

std::unique_ptr是C++11标准引入的,是一个独占的智能指针,不能被复制,只能被移动。

当离开unique_ptr的作用域时,会自动释放空间。

1
2
3
4
5
6
7
8
9
10
11
12
13

#include <iostream>
#include <memory>

int main(){
{
std::unique_ptr<int> p = std::make_unique<int>(10);
//或者std::unique_ptr<int> p(new int(10));但上面那种有安全保证
// std::unique_ptr<int> p1 = p; //错误,不能被复制
}
// 离开作用域(内部的花括号),自动释放空间
}

6.5.2 std::shared_ptr

std::shared_ptr是一个共享的智能指针,可以被复制,当最后一个shared_ptr被销毁时,会自动释放空间。

std::shared_ptr中有一个引用计数,当有shared_ptr指向一个对象时,引用计数加1,当shared_ptr被销毁时,引用计数减1,当引用计数为0时,释放空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#include <iostream>
#include <memory>

class Entity{
public:
Entity(){
std::cout << "Created Entity!" << std::endl;
}
~Entity(){
std::cout << "Destroyed Entity!" << std::endl;
}

};


int main() {
std::shared_ptr<Entity> sptr = std::make_shared<Entity>();
{
std::shared_ptr<Entity> p1 = sptr; //正确,可以被复制
}
std::cin.get();
}

6.5.3 std::weak_ptr

std::weak_ptr是一个弱引用的智能指针,和shared_ptr一起使用,不会增加引用计数,当最后一个shared_ptr被销毁时,会自动释放空间。weak_ptr可以通过lock()方法获取一个shared_ptr,如果shared_ptr不存在,返回一个空的shared_ptr。weak_ptr可以查询引用计数,但不能访问对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#include <iostream>
#include <memory>

class Entity{
public:

Entity(){
std::cout << "Created Entity!" << std::endl;
}
~Entity(){
std::cout << "Destroyed Entity!" << std::endl;
}

};


int main() {
std::weak_ptr<Entity> wptr;
{
std::shared_ptr<Entity> sptr = std::make_shared<Entity>();
wptr = sptr;
{
std::shared_ptr<Entity> p1 = wptr.lock(); //正确,可以被复制
std::cout << wptr.use_count() << std::endl;
}
}
std::cout << wptr.use_count() << std::endl;
}

6.6 继承

在类的定义中,使用:来指定继承的类,可以指定访问权限,可以是public,protected,private,默认是private。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class A{
protected:
int a;


public:
A():a(1){};
int geta()const{
return a;
}

};

class B:public A{
public:
int b;
void seta(const int& a){
this->a = a;
}
};


int main(){
B *b = new B();
b->seta(5);
std::cout << b->geta() << std::endl;
}
  • 子类可以访问父类的非私有成员。
  • 子类可以重写父类的方法(除了构造函数,析构函数,拷贝函数,重载运算符,友元函数)。
  • 用public继承时,父类的public成员在子类中是public,父类的protected成员在子类中是protected
  • 用protected继承时,父类的public成员在子类中是protected,父类的protected成员在子类中是protected
  • 用private继承时,父类的public成员在子类中是private,父类的protected成员在子类中是private

C++中的继承是单继承,但是可以多重继承,即一个类可以有多个父类。

1
2
3
4
5

class C:public A, public B{

}

但是多重继承会引起菱形继承问题,即一个类有多个父类,而这些父类又有共同的父类,这样就会出现多次继承,导致数据冗余,内存浪费。下面章节详细讨论。

6.7 重载

重载是指在同一个作用域中,函数名相同,但是参数列表不同,返回值可以不同。可分为函数重载和运算符重载

6.7.1 函数重载

函数重载即在同一个作用域中,函数名相同,但是参数列表不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int add(int a, int b){
return a+b;
}

float add(float a, float b){
return a+b;
}

int add(int a, int b, int c){
return a+b+c;
}

int main(){
std::cout<<add(1,2)<<std::endl;
std::cout<<add(1.1,2.2)<<std::endl;
std::cout<<add(1,2,3)<<std::endl;
}

6.7.2 运算符重载

假设有一个类代表的是一个二维向量,如果想将这两个类的对象相加得新的对象。此时运算符重载就有作用。

c++中大部分运算符支持重载。

1
2
3

返回值类型 operator 运算符(参数) {} ;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

class vector{

public:
int x,y;
vector(int x,int y):x(x),y(y){};
vector():x(1),y(1){};

vector operator+(const vector& other)const{
return vector(x+other.x,y+other.y);
}

vector operator*(const vector& other)const{
return vector(x*other.x,y*other.y);
}

};

//因为<<是对ostream的重载,所以写在类外
std::ostream& operator<<(std::ostream& stream, const vector& other) {
stream << other.x << " " << other.y;
return stream;
}


int main(){
vector a(1,2);
vector b(3,4);
vector c = a+b;
std::cout<<c<<std::endl;
int d=8;
int *const e = &d;
*e +=1;
std::cout<<d<<std::endl;
return 0;
}

可重载的运算符:

  • 双目算术运算符:+, -, *, /**
  • 关系运算符: ==, !=, >=, <=, >, <
  • 逻辑运算符: ||, &&, !
  • 单目运算符: +(正), -(负), *(指针), &(取地址)
  • 自增自减运算符: ++, –
  • 位运算符: |, &, ~(按位取反), ^(按位异或), <<, >>
  • 赋值运算符: =, +=, -=, *= , /=, %=, &=, |=, ^=, <<=, >>=
  • 空间申请与释放:new, delete, new[], delete[]
  • 其他运算符: ()(函数调用), ->(成员访问), ,(逗号),

重载,重写,重定义的区别:

  • 重载:在同一个作用域中,函数名相同,但是参数列表不同
  • 重写:子类重写父类的方法
  • 重定义:在子类中定义与父类同名的非虚函数(参数可以不同)

6.8 虚函数

  • C++中多态即一种接口,多种方法,是通过虚函数实现的。

  • 虚函数是在基类中声明的,用virtual关键字修饰,子类中可以重写(override)这个函数。

  • 当一个类中有虚函数时,会在对象的内存中存储一个虚函数表(virtual table),这个表中存储了虚函数的地址,当调用虚函数时,会根据对象的虚函数表找到对应的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Entity{
public:
//虚函数
virtual std::string GetName(){
return "Entity";
}

};

class Player:public Entity{
public:
private:
std::string m_Name;
public:
Player(const std::string& name):m_Name(name){}

//重写虚函数(override可以不写,但写了会对重写进行检查是否有对应的虚函数)
std::string GetName() override{
return m_Name;
}
};

当虚函数=0时,称为纯虚函数,这个类就是抽象类,不能被实例化,只能被继承,子类必须重写这个函数。

1
2
3
4
5
6
7
8
9
10
11
12
class Entity{
public:
virtual std::string GetName() = 0; //纯虚函数
};

class Player:public Entity{
public:
std::string GetName() override{ //重写纯虚函数
return "Player";
}
};

6.9 菱形继承

菱形继承是指一个类有多个父类,而这些父类又有共同的父类,这样就会出现多次继承,导致数据冗余,内存浪费。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A{
public:
int a;
};

class B:public A{
public:
int b;
};

class C:public A{
public:
int c;
};

//此时D类有两个A类的成员
class D:public B,public C{
public:
int d;
};

解决方法:

  1. 虚继承

继承的时候在可能会出现重复的类上加上virtual关键字,这样就不会出现多次继承,只会继承一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A{
public:
int a;
};

class B:virtual public A{
public:
int b;
};

class C:virtual public A{
public:
int c;
};

class D:public B,public C{
public:
int d;
};

6.10 友元函数

友元函数是指可以访问类的私有成员的函数,但不是类的成员函数。
即在类的内部声明函数为友元函数(加前缀),在类的外部定义这个函数,这个函数就可以访问类的私有成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

//1. 外部友元函数
class A{
private:
int a;
public:
A(int a):a(a){}

friend void printA(A a);
};

void printA(A a){
std::cout<<a.a<<std::endl;
}



//2. 友元类,即B类可以访问A类的私有成员

class A{
private:
int a;
public:
A(int a):a(a){}

friend class B;
};

class B{
public:
void printA(A a){
std::cout<<a.a<<std::endl;
}
};


//3. 友元成员函数,即B类的成员函数可以访问A类的私有成员

class A{
private:
int a;
public:
A(int a):a(a){}

friend void B::printA(A a);
};

class B{
public:
void printA(A a){
std::cout<<a.a<<std::endl;
}
};




七、模板

模板是一种泛型编程的方法,可以实现代码的复用。

  • 定义:在要用模板的函数或类上面加上template关键字,然后在尖括号中声明模板参数,然后在函数或类中使用这个模板参数。

  • 使用:在调用模板函数或类时,需要在名字后面加尖括号,尖括号中指定模板参数。

    7.1 函数模板

函数模板是一种通用的函数,可以用于不同的数据类型。

1
2
3
4
5
template <typename T, int N>

T add(T N, T b){
return N+b;
}
1
2
3
4
5
6
7
8
9
10
11
12

template <typename T>

T add(T a, T b){
return a+b;
}

int main(){
std::cout<<add(1,2)<<std::endl;
std::cout<<add(1.1,2.2)<<std::endl;
}

7.2 模板参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//N是模板参数,能使输入的数组大小不定
template <int N>
//这样是对的,因为N是当作一种替代,在编译时就会被替换成相应的值
void PrintArray(const std::array<int, N>& array){
for(int i=0;i<N;i++){
std::cout<<array[i]<<std::endl;
}
}

int main(){
std::array<int, 5> array = {1,2,3,4,5};
PrintArray<5>(array);
}


/*
template <int N>
void PrintArray(int N) {
for(int i = 0; i < N; i++){
std::cout << i << std::endl;
}
}

这样是错误的,因为N是当作一种替代,在编译时就会被替换成相应的值,这样就会和函数的参数冲突(如果调用时printArray<5>(5),相当于函数参数N变成了常量5,而不是变量了
*/

7.3 类模板

类模板是一种通用的类,可以用于不同的数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14

template <typename T>

class A{
public:
T a;
A(T a):a(a){}
};

int main(){
A<int> a(1);
A<std::string> b("hello");
}




八、lambda表达式

lambda表达式是一种匿名函数,可以用于定义函数,可以捕获外部变量。通常用于某些函数只会被调用一次的情况。

捕获是指在lambda表达式中使用外部变量。

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
[捕获列表]  (参数列表)  {函数体}

[捕获列表] (参数列表) mutable(可选) 异常声明(可选) ->返回类型(可选) {函数体}

捕获列表:
[],表示不捕获任何外部变量;
[=],表示以值的方式捕获所有外部变量;
[&],表示以引用的方式捕获所有外部变量;
[a, &b],表示以值的方式捕获a,以引用的方式捕获b;
[this],表示以值的方式捕获this指针;
[a, b],表示以值的方式捕获a和b;
[=, &a],表示以引用的方式捕获所有外部变量,但是a以值的方式捕获。

例子:

  1. 不捕获外部变量

    1
    2
    3
    4
    5
    6
    //lambda返回的是一个函数对象,需要用auto接收
    int main(){
    auto plus = [] (int v1, int v2) -> int { return v1 + v2; };
    int sum = plus(1, 2);
    return 0;
    }

    或者:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    #include <iostream>
    #include <vector>
    #include <algorithm> // 为了使用std::copy_if
    #include <iterator> // 为了使用std::back_inserter

    int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int> filteredNumbers;

    // 使用 lambda 表达式过滤大于5的元素, 并将它们添加到 filteredNumbers
    std::copy_if(numbers.begin(), numbers.end(), std::back_inserter(filteredNumbers),
    [](int x) { return x > 5; }); // Lambda 表达式

    std::cout << "Filtered Numbers: ";
    for(int num : filteredNumbers) {
    std::cout << num << " ";
    }
    std::cout << std::endl; // 输出:Filtered Numbers: 6 7 8 9 10

    return 0;
    }

  2. 捕获外部变量

    1
    2
    3
    4
    5
    6
    7
    int main(){
    int a = 1;
    int b = 2;
    auto plus = [a, b] () -> int { return a + b; };
    int sum = plus();
    return 0;
    }



九、STL

STL(Standard Template Library)是C++标准模板库,是一系列的模板类和函数,提供了通用的模板类和函数,包括算法、容器、迭代器、函数对象等。

9.1 容器

9.1.1 vector(数组)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
头文件:
#include <vector>

一维初始化:
std::vector<int> a;
std::vector<int> a(10); //初始化大小为10
std::vector<int> a(10, 1); //初始化大小为10,值为1
std::vector<int> a = {1, 2, 3, 4, 5}; //初始化为{1, 2, 3, 4, 5}

拷贝初始化:
std::vector<int> a(10,1);
std::vector<int> b(a); //拷贝初始化
std::vector<int> c = a; //拷贝初始化

二维初始化:
vector<vector<int>> a(10, vector<int>(10, 1)); //初始化大小为10*10,值为1


方法:
a.front(); //返回第一个元素
a.back(); //返回最后一个元素
a.push_back(1); //在末尾添加元素
a.pop_back(); //删除末尾元素
a.size(); //返回元素个数
a.empty(); //判断是否为空
a.clear(); //清空
a.insert(a.begin()+1, 2); //在指定位置插入元素,即将2插入到a[1]的位置
a.erase(a.begin()+1); //删除指定位置的元素
a.erase(a.begin()+1, a.begin()+3); //删除指定范围的元素,即删除a[1]和a[2],不包括a[3]
a.resize(10); //改变大小
a.begin(); //返回指向第一个元素的迭代器
a.end(); //返回指向最后一个元素的下一个位置的迭代器
std::sort(a.begin(), a.end()); //排序


访问:
下标访问:
a[1]; //访问第二个元素

迭代器访问:
vector<int>::iterator it;
for(it = a.begin(); it != a.end(); it++){
std::cout<<*it<<std::endl;
}

9.1.2 stack(栈)

1
2
3
4
5
6
7
8
9
10
11
12
头文件:
#include <stack>

初始化:
std::stack<int> a;

方法:
a.push(1); //入栈
a.pop(); //出栈
a.top(); //返回栈顶元素
a.size(); //返回元素个数
a.empty(); //判断是否为空

9.1.3 queue(队列)

1
2
3
4
5
6
7
8
9
10
11
12
13
头文件:
#include <queue>

初始化:
std::queue<int> a;

方法:
a.push(1); //入队
a.pop(); //出队
a.front(); //返回队首元素
a.back(); //返回队尾元素
a.size(); //返回元素个数
a.empty(); //判断是否为空

9.1.4 deque(双端队列)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
头文件:
#include <deque>

初始化:
std::deque<int> a;

方法:
a.push_back(1); //在末尾添加元素
a.pop_back(); //删除末尾元素
a.push_front(1); //在头部添加元素
a.pop_front(); //删除头部元素
a.front(); //返回第一个元素
a.back(); //返回最后一个元素
a.size(); //返回元素个数
a.empty(); //判断是否为空
a.clear(); //清空
a.insert(a.begin()+1, 2); //在指定位置插入元素,即将2插入到a[1]的位置
a.erase(a.begin()+1); //删除指定位置的元素
a.erase(a.begin()+1, a.begin()+3); //删除指定范围的元素,即删除a[1]和a[2],不包括a[3]
a.resize(10); //改变大小
a.begin(); //返回指向第一个元素的迭代器
a.end(); //返回指向最后一个元素的下一个位置的迭代器
std::sort(a.begin(), a.end()); //排序

9.1.5 list(链表)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
头文件:
#include <list>

初始化:
std::list<int> a;

方法:
a.push_back(1); //在末尾添加元素
a.pop_back(); //删除末尾元素
a.push_front(1); //在头部添加元素
a.pop_front(); //删除头部元素
a.front(); //返回第一个元素
a.back(); //返回最后一个元素
a.size(); //返回元素个数
a.empty(); //判断是否为空
a.clear(); //清空
a.insert(a.begin()+1, 2); //在指定位置插入元素,即将2插入到a[1]的位置
a.erase(a.begin()+1); //删除指定位置的元素
a.erase(a.begin()+1, a.begin()+3); //删除指定范围的元素,即删除a[1]和a[2],不包括a[3]
a.resize(10); //改变大小
a.begin(); //返回指向第一个元素的迭代器
a.end(); //返回指向最后一个元素的下一个位置的迭代器
std::sort(a.begin(), a.end()); //排序

9.1.6 map(映射)

map是一种键值对的容器,可以通过键来访问值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
头文件:
#include <map>

初始化:
std::map<int, std::string> a;

方法:
a.insert(std::pair<int, std::string>(1, "a")); //插入元素
a.erase(1); //删除元素
a.size(); //返回元素个数
a.empty(); //判断是否为空
a.clear(); //清空
a.begin(); //返回指向第一个元素的迭代器
a.end(); //返回指向最后一个元素的下一个位置的迭代器
a.find(1); //查找元素,返回指向该元素的迭代器

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::map<int, std::string> a;
a.insert(std::pair<int, std::string>(1, "a"));
a.insert(std::pair<int, std::string>(2, "b"));
a.insert(std::pair<int, std::string>(3, "c"));

std::map<int, std::string>::iterator it;
for(it = a.begin(); it != a.end(); it++){
std::cout<<it->first<<" "<<it->second<<std::endl;
}

std::map<int, std::string>::iterator it = a.find(1);
if(it != a.end()){
std::cout<<it->first<<" "<<it->second<<std::endl;
}

9.1.7 set(集合)

集合是一种不包含重复元素的容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
头文件:
#include <set>

初始化:
std::set<int> a;

方法:
a.insert(1); //插入元素
a.erase(1); //删除元素
a.size(); //返回元素个数
a.empty(); //判断是否为空
a.clear(); //清空
a.begin(); //返回指向第一个元素的迭代器
a.end(); //返回指向最后一个元素的下一个位置的迭代器
a.find(1); //查找元素,返回指向该元素的迭代器

9.1.8 string(字符串)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
头文件:
#include <string>

初始化:
std::string a;

方法:
a.size(); //返回字符串长度
a.empty(); //判断是否为空
a.clear(); //清空
a.insert(1, "a"); //在指定位置插入字符串
a.erase(1); //删除指定位置的字符
a.erase(1, 3); //删除指定范围的字符
a.find("a"); //查找字符串,返回指向该字符串的迭代器
a.substr(1, 3); //返回指定范围的子字符串
a.begin(); //返回指向第一个字符的迭代器
a.end(); //返回指向最后一个字符的下一个位置的迭代器(注意!:是最后一个字符的下一个位置)

9.1.9 array(数组)

1
2
3
4
5
6
7
8
9
10
11
12
头文件:
#include <array>

初始化:
std::array<int, 5> a;

方法:
a.size(); //返回数组长度
a.empty(); //判断是否为空
a.fill(1); //填充数组
a.begin(); //返回指向第一个元素的迭代器
a.end(); //返回指向最后一个元素的下一个位置的迭代器

9.2 迭代器

迭代器是一种指针,用于遍历容器中的元素。

1
2
3
4
5
std::vector<int> a = {1, 2, 3, 4, 5};
std::vector<int>::iterator it;
for(it = a.begin(); it != a.end(); it++){
std::cout<<*it<<std::endl;
}
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2020-2024 nakano-mahiro
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信