TreeMind树图在线AI思维导图
当前位置:树图思维导图模板资格考试计算机Linux C/C++后台学习路线思维导图

Linux C/C++后台学习路线思维导图

  收藏
  分享
免费下载
免费使用文件
阔落半糖少冰 浏览量:322023-04-27 22:58:50
已被使用2次
查看详情Linux C/C++后台学习路线思维导图

Linux C/C++后台学习路线

树图思维导图提供 Linux C/C++后台学习路线 在线思维导图免费制作,点击“编辑”按钮,可对 Linux C/C++后台学习路线  进行在线思维导图编辑,本思维导图属于思维导图模板主题,文件编号是:e683b64d9982c7a2217d59a6ce964e98

思维导图大纲

Linux C/C++后台学习路线思维导图模板大纲

1、C++语法(6-8周)

1 基础知识点

程序员的第一个程序

#include<iostream> using namespace std; int main() { cout << "hello world~" << endl; //输出 system("pause"); // 暂停 return 0; }

注释

功能

让其他人能看懂代码

符号

//

单行注释

c++ 标准注释

/* code */

多行注释

C语言特有

问题

注释结尾不确定

利用预处理实现多行注释

#if 0 #endif

主函数

应用程序入口,操作系统调用程序的接口

main

一个项目只能有一个main函数

单个文件只能出现一个

多个文件只能一个文件中有一个

常见的五种

int main() { return 0; }

c++标准主函数形式

int main(void) { return 0; }

C语言标准主函数形式

void 表示不接受任何参数

无void 表示参数类型和数量不确定

int main(int argc, char* argv[]) { return 0; }

c/c++标准主函数形式,使用命令行参数

main() { }

老标准支持的写法,现在的 C语言还支持这种写法

但是尽量不要这么写

c++不支持这种写法

void main() { }

不提倡

c++之父说,这种形式的主函数,在C语言和c++中,都没有被定义

书上说,这种主函数写法逻辑上符合,而且有很多系统支持,但是考虑到代码的移植性,建议用标准型式。标准形式所有系统都支持。

头文件

#include<iostream.h>

老版头文件,继承C语言的头文件习惯,vc6.0可用,vs正常情况下不可以用

#include<iostream> using namespace std;

标准头文件,vc,vs均可用

命名空间

功能:区分同名变量或者函数

创建

namespace name { code; };

名字不能重复

3种使用方法

打开 using namespace name;

name::变量名/函数

:: 作用域运算符

using name::成员;

指定开放某个特定成员

输入输出

c++:

cout

是个对象,不是关键字,也不是函数

输出

常量

cout << "hello C3~" ;

cout << ' ' ;

cout << 12.12;

变量

char c = 'a'; int a = 1; double b = 2.1; char *p = "hello C3~"; cout << c << ' ' << a << ' ' << b << ' ' << p;

可以输出一个,也可以连续输出,怎么样好看怎样写

这个比printf智能(需要指定类型输出%c,%d,%s...),cout可以自动识别变量类型

输出控制

控制符

endl

屏幕光标移动到下一行开头

重起一行,刷新缓冲区

换行符

\n

重起一行

异同

重起一行显示,屏幕光标移动到下一行开头

endl,多了一个刷新缓冲区的操作,这个操作,会使缓冲的字符立刻显示到屏幕上。 \n,则不保证这一点,也就是说,在一些系统上,\n的显示会慢半拍。常用的这些系统,都不会这样,也就是说,显示这个功能,基本没有区别。

endl的效率,是慢的。多了操作

cin

是个对象,不是关键字,也不是函数

输入

变量

char c = 'a'; int a = 1; double b = 2.1; char *p = "hello C3~"; cin >> c >> a >> b ; cout << c << ' ' << a << ' ' << b << ' ' << p;

可以输入一个,也可以连续输入,怎么样好看怎样写

这个比scanf智能(需要指定类型输出%c,%d,%s...),cin可以自动识别变量类型

c: scanf printf

数据类型

基本数据类型

字符型

char

内存大小

表示范围范围

数值类型

整形

short

int

long

long long

浮点型

float

double

long double

构造类型

数组

[ ]的三种作用

声明变量的时候有[ ],表示声明的是数组变量

函数参数有[ ],此时表示指针

地址+[ ],表示下标运算

一维数组

字符数组/字符串

定义

以'\0'结尾的字符数组

输出输入

c++:cout << name; cin >> name;

C: printf("%s",name); scanf("%s",name);

字符串的声明方式(四种形式)

操作

库函数

strcmp(),strlen(),strcpy,strcat()...等等

其他类型的数组

注意区分初始化和赋值的区别

遍历

注意越界问题

地址

取地址运算符:&

a == &a[0]

首元素的首地址

&a[0], &a[1].....

单个元素地址

&a

数组的地址

二维数组

声明和初始化

地址

&a[1], &a[2], &a[0] == a

一维数组元素地址

&a[0][1], &a[1][0] == a[1]....&a[0][0] == a[0] ;

取元素地址

&a

二维数组的地址

结构体

struct

结构体类型声明方法

有名字,无名字

结构体变量的声明方法

初始化

成员赋值

成员调用方法

取成员运算符

.

->

结构体大小

内存对齐

链表

单向链表

双向链表

c++独有

声明变量可以不用struct关键字

可以放函数成员

C语言的不可以放函数成员,但是可以放函数地址、

是一个特殊的类

联合/共同体

union

特点

所有成员共享内存

大小

最大的成员的大小

一般初始化最大的成员

延伸

大小端模式

大小端模式的测试方法

枚举

enum

声明以及使用

使用有意义的字符串

大小

4字节

实为int类型的数的集合

指针

内存申请与释放

C++

new

申请单个空间

int *p = new int; int *p = new int(10); 初始化一个值

类型一定要匹配上

struct Node{code;}; Node *p = new Node;

其他类型同理

申请数组空间

int *p = new int[10];

memset(起始地址,字节数,设置的值),设置内存初始值

堆区的空间不像是栈区的那种,可以在声明的时候初始化。

其他类型同理

失败返回一个NULL,同C语言的malloc一样

delete

delete p; <==> new type;

对于标准来说,不匹配释放,结果是不确定的。

delete [ ] p;<==> new type [count];

一定要加上,

delete NULL 是安全的, free(NULL)会崩溃的

C: malloc() free()

区别

new delete 可以触发构造和析构

同时释放一块空间大于1次,是不行的

指针声明和空间分配方式不同,使用完全相同,所以说,在c++里,除了对象空间申请之外,用malloc 和 free是完全可以的,

指针类型

基本数据类型的指针

数组指针 与 指针数组

一维数组

二维数组

二级指针

函数指针

结构体指针

指针的大小

地址+1 是加了一个类型的大小

64bit编译器

8字节

32bit编译器

4字节

*的三种作用(c/c++)

声明的时候有*,表示指针变量

*+地址,表示地址操作符,取内容

数字*数字,表示乘法

引用变量

概念

引用是已定义的变量的别名(另一个名称),两者用法完全一样了

同类理解

typedef 是给类型起别名

声明与定义

基本数据类型变量的引用

int b = 12; int &c = b; int &d = b; int &e = d;

定义的时候就要初始化

不能指向其他的了

看地址

其他类型同理

常量的引用

const int &n = 12; const char &c = 'a'; const float &f = 123.123f;

复合数据类型的引用

数组的引用

int a[2]; int (&b)[2] = a; int a[2][3]; int (&c)[2][3] = a;

方式同数组指针一样

结构体的引用

类型 & 名字 = 结构体实例;

指针的引用

int* p = NULL; int* (&d) = p;

引用与函数

做函数参数

最主要的功能

修改参数的值

void Change(int& a) { a = 12; }

void Change(int a) { a = 12; }

void Change(int* a) { *a = 12; }

交换两个数的值

void ExChange(int& a, int& b) { int ntemp = a; a = b; b = nTemp; }

引用与返回值

不要引用局部变量就行

注意:操作非法内存的结果是未知的

引用与指针的区别

1、引用声明就要初始化,指针不用 int *p = NULL;

2、引用不能指向其他变量了,指针则可以任意指向。p = &a; p = &d;

3、引用不占存储空间,指针占空间

4、引用效率更高,指针式间接操作

5、引用更安全,指针可以偏移

6、指针更灵活,直接操作地址,指针更通用c语言和c++都行

&的三种作用

声明变量的时候有&,表示引用

变量前边+&,表示取地址

数&数,表示位与运算

运算符

优先级

结合性

运算符优先级表

这个表格不用记,写代码的时候直接加括号

流程结构

顺序

由上向下一步一步执行

循环

可控循环的三要素

循环控制变量有初始值

循环执行条件

真 == 1;

假 == 0;

初始值的变化

三种结构

入口条件循环

for(初始值;条件;变化)

for循环结构执行次序

while(条件)

退出条件循环

do{} while()

至少执行一次,循环体内部语句

continue

结束本次循环,继续下一次循环

break

跳出所在循环

c++增强的for循环

变量定义的位置

vc和vs结构内定义循环控制变量的作用域区别

分支跳转/选择

if (条件){} else if(条件){} else{}

switch(ID) { case ID: break;}

goto

可以根据逻辑,写成循环结构或者跳转结构

建议不用

函数

声明,定义

函数类型

无参数,无返回值

C:标准C语言,函数没参数需要写个void

c++:不用写void

无参数,有返回值

return ;

返回局部变量

有参数,有/无返回值

传值与传址

参数缺省值/默认值

形式

int fun(int a = 0, char c = 'b', float f = 12.12 );

全部指定

int fun(int a , char c = 'b', float f = 12.12 );

部分指定

一定是从右向左,逐个指定

int fun(int a = 12, char c , float f = 12.12 );

随意指定是会报错的

使用

有默认值得参数,传递实参会覆盖默认值,不传递实参会使用默认值,极大的增加了函数调用的灵活性

注意

使用函数原型

函数声明时候写默认

函数定义处不要写

不使用函数原型

直接写就行了

函数指针

函数重载

定义

同一作用域内

相对的一个位置,大家理解即可

函数名字相同

参数列表不同

参数类型不同

这两个条件是 或 的关系

参数个数不同

形式

void fun(int a); void fun(int a, int b); void fun(char c); void fun(float f, double d);

调用

系统会根据参数的形式,自动找到要调用的函数

例子

int main() { fun(1); fun('a'); fun(2,3); fun(12.13f, 123.123); }

何时使用,或者有什么好处

函数调用更灵活了

注意

默认参数和重载结合使用,可能会造成调用不明确

例子

void fun1(int a, int b, int c = 0); void fun1(int a, int b); int main() { fun(1,2); //传递两个参数,编译正常,运行时候就会报错 }

返回值不作为函数重载的条件

int fun(); void fun(); //这种声明方式报 重定义 错误

参数是浮点型float,double的护卫重载的函数,一定要注意参数传递

递归函数

展开再理解

文件操作

文件操作流程

打开文件

fopen

文件的打开方式

文本模式

二进制模式

操作文件

fread(),fwrite(),fgets().....

关闭文件

fclose()

文件写入磁盘的钥匙

内存管理

位运算

进制转换

二进制与16进制,十进制与16进制, 十进制与2进制

位运算符

&,|,~,^

区别于逻辑运算符

内存分区

变量的作用域

堆区,栈区,全局区,静态/全局常量区,代码区

1 内存分配未成功,你却使用

malloc

2 内存虽然分配成功,但是没有初始化你就引用他

3 内存分配成功,并且初始化成功,但是操作的时候超过内存边界

4 内存泄露

5 内存释放了,你却继续使用

6 内存碎片

7 内存

类型转换

隐是类型转换

显示类型转换

强制类型转换

2 类(封装、继承、多态)

类和对象

类和面向对象的关系

面向对象是一种编程思想

类是一个语法

意义:面向对象的编程思想,要以这个语法(类)来实现。 大家暂时不要强行理解面向对象这种思想,因为这个理解是要基于很多项目经验的,不是一朝一夕就能领悟的。 学好类,就行了

定义:具有相同属性和行为的对象的集合(人类,就是一个人的集合,胖胖秦就是这个类的一个具体个体,或者叫对象)

类实例

class CPeople { public: int age; void Test() { age = 12; cout << age << endl; } }; int main() { CPeople op; op.Test(); CPeople* op1 = new CPeople; op1->Test(); delete op1; return 0; }

类声明

class 类名 { };

跟结构体基本是一样的,只不过关键字是class

结构体是类的一个特定情况

声明对象

CPeople op;

CPeople* op1 = new CPeople;

成员调用

栈区普通对象

对象.成员

op.Test();

堆区指针对象

对象->成员

op1->Test();

delete op1;

类的所有成员(个别特殊static),必须通过对象访问

访问修饰符

关键字

private

类内可见

类内不写访问修饰符,默认是private

protected

类内以及子类可见

public

类外可见

c++的结构体,默认是public

友元

关键字

friend

友元函数

friend void fun();

需要声明

friend int main();

不需要声明

友元类

使用protected成员有两种方法

继承

友元

使用private成员

友元

特点

不受访问修饰符影响

可以有多个友元

缺点:破坏了类的封装性,不是迫不得已,不要用

接口,

作用范围

书写位置开始,一直到下个修饰符,或者类结尾的花括号 }

拓展功能

作为类内成员分类的工具,这个,修饰符,写多少都行

安全性

函数成员

构造函数

产生

普通数据成员不能够在类内直接赋值,因为只有对象创建的时候才分配空间 那么,我们的数据如何赋予初始值呢。我们可以定义一个成员函数,对成员统一赋值

void init(int b) { a = a; }

形式

类名(参数列表){}

无返回值

作用

对数据成员赋初始值

调用

对象定义的时候

栈区对象

堆区对象

声明指针并不会调用构造函数,new空间的时候调用

类型

默认构造函数

什么都不做,即空的

只要宏观声明的构造函数,默认的就没有了

无参数

有参数构造函数

通过对象传递

可以指定默认值

多个构造函数构成重载

成员函数定义

类内定义

类外

类内声明

意义是用于多文件

类外定义

初始化列表

初始化与赋值的区别

意义上

初始化是一个变量或者对象产生之时就赋予一个初始值,伴随性质

赋值是一个变量或者对象产生之后的任意时刻可以赋予一个值,随意性质

宏观代码上

基本数据类型

作用相同

数组,结构体

初始化,和赋值的形式不同

作用相同

引用,const

只能初始化

不能赋值

函数定义和声明

形式

构造函数之后加个冒号:a(1),b(2)

不是花括号之后

作用

跟构造函数的区别

基本数据类型,用哪个都行

引用,const必须用初始化列表

对数据成员进行初始化

可通过数值对数据成员初始化

可通过构造函数参数对数据成员进行初始化

可通过成员之间相互初始化

成员初始化的顺序

初始化的方式很多,大家根据自己的需要用

执行顺序

在构造函数之前

引用和const

引用

引用成员

引用参数

引用类外

const

参数

常量

注意点

多个构造函数,初始化列表绑定所在的构造函数

数组和结构体如何使用初始化列表

数组

CStu() : arr()

vc无效果

vs有效果

通常设置设置数组元素全为0的方法

memset

for循环

结构体

可直接赋值

用初始化列表反而增加了复杂性

析构函数

作用

清理工作

比如我们用new给成员申请了空间,析构函数内可以释放掉

调用时间决定了他的主要作用

形式

~类名()

只有一个,没有参数

没有重载

默认析构函数

什么都不做,类比默认构造函数

调用

对象声明周期结束时,自动调用

局部对象

临时对象

作用域

所在语句

指针对象

delete

默认

malloc 和 new的区别

new会触发构造函数,malloc不会

free 和delete区别

delete会触发析构函数,free不会

常函数

形式

void fun() const {;}

构造和析构 不可以是常函数

特点

可以使用数据成员,不能修改数据成员

对函数的功能有更明确的限定

常函数的this指针是 const CStu*

常对象只能调用常函数,不能调用普通函数

static

形式

static int a;

static void fun(){}

使用方式

对象调用

类名作用域

静态成员

类外初始化

无static

静态常量整型数据成员可以直接进行初始化

static const float a = 13.12f;

不行

static const int a = 13.12f;

整形

不使用循环,来个自加1

静态成员函数

无this

不能调用成员成员,可以调用静态成员

可以作为一种指挥该类所有对象的作用

他是属于类的属性,不是对象,即所有对象共有一个

可以通过类名调用

可以通过对象调用

拷贝构造/复制构造:copy

形式

CStu(const CStu&)

本质即构造函数

参数是本类的常引用

何时调用

1、新建一个对象,并将其初始化为同类现有对象

CStu a;

声明一个对象

1、CStu a1(a);

2、CStu a2 = a;

3、CStu a3 = CStu(a);

4、CStu* a4 = new CStu(a);

赋值不会的

CStu s; CStu p; s = p;

2、当程序生成对象副本时

函数参数传递对象的值

函数返回对象

有何功能

默认的复制构造函数,逐个复制非静态成员(成员的复制成为浅复制)值,复制的是成员的值

系统默认的这个又叫浅拷贝

实践一下,模仿一下默认的

模仿的这个也是浅拷贝

同一个类的多个对象,内存排布是一样的,地址不同

演示问题

指针成员

构造分配空间

析构释放空间

深拷贝

指针成员不能直接赋值,要用内存拷贝,memcpy,strcpyd等

解决拷贝构造所引发的,指针成员二次释放崩溃的问题的方式

深拷贝

传地址

传引用

内联函数

常规函数调用过程

调用时,根据函数地址

跳到函数代码空间,执行指令

执行完,再跳转到调用的位置

综合:来回跳跃+记录跳跃的位置==一定的系统开销(资源+时间)

内联函数

inline

函数声明要加inline

函数定义要加inline

注意:只写声明位置不管事儿

作用

用相应的代码替换调用

比常规函数稍快

代价是占用更多内存

常规函数和内联函数如何选择

特点

时间和空间

1看实际需要

空间换时间

时间换空间

2看性价比

实际

函数代码少,流程直接,调用频繁

循环里的

编译器智能

程序猿请求将函数作为内联函数时,编译器不一定会答应,

函数体过大

递归不能是内联函数

效果:写了等于没写,按常规函数进行编译

这个特性是编译器特性,即不是所有编译器都实现了这一功能

内联函数比宏功能更强

测试一个参数宏

测试参数内联函数

类与内联函数

类内定义都是内联函数

显示定义

隐式定义

定义在外

有inline 是内联

没有inline不是内联

内联函数与多文件

内联函数可以有多个定义,多个定义必须完全一致

所以通常,内联函数写在头文件里

数据成员

相对特殊

引用成员

初始化列表初始化

const成员

初始化列表初始化

静态成员

类外初始化

无this指针

静态常量成员

可在类内直接初始化

也可在类外初始化

指针成员

注意拷贝构造产生的问题

常规

其他类型

this

作用

区分同名的

是指向当前对象的指针

所以我们可以通过指针,访问成员

对象创建的时候才有的

类型

对应对象的类的指针类型

this指针不是成员

this作用域是在类内部,系统默认传递给函数(非静态函数)的隐含参数

继承

继承小实例

class CPeople { public: int hands; int head; void speak(){ } void study(){ } }; class CXiaoming : public CPeople { public: int age; char *name; void speakChinese(){ } void work() { } } class CXiaohua : public CPeople { public: int age; char *name; void alllanguage(){ } } int main() { CXiaoming xiaming; xiaoming.hands;..... CXiaohua xiaohua; xiaohua.hands;...... return 0; }

继承的作用

代码的重用性

继承的格式

class CXiaoming : public CPeople

基类或者叫父类

派生类或者叫子类

可以继承很多层

原理都一样

继承对象的声明以及成员调用调用

普通对象

指针对象

基类也可以自己创建对象

继承的限定词

private

父类中public,protected,在子类中为private,降低访问权限

protected

父类的public成员,子类中为protected,即为降低权限

public

父类如何子类如何

成员的继承

函数成员

构造函数

以无参构造演示,子类和父类构造函数的执行顺序

先调用父类的,父类还有父类就继续向上

父类有参数的构造,需要通过子类初始化列表来传递参数

只关注自己父亲的

多个构造函数选择传递

默认是无参的

参数列表写谁,调用谁

析构函数

调用顺序

由辈分小的到辈分大的

覆盖

父类和子类中出现同名的成员时,C++采用的一种处理方式,就叫覆盖

数据成员同名

类内 ,子类覆盖父类,可以用类名作用域区分

类外: 类名作用域区分

父类子类函数名字相同

子类覆盖父类

使用时可以通过类名作用域区分

父类子类的函数没有重载关系

友元不能被继承

继承

静态只有一份儿

虚继承

多继承

多个基类

子类的子类

虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的

父类叫做虚基类

解决多继承中访问不明确的问题

不建议用,结构复杂,内存开销比较大

多态与虚函数

多态与虚函数

多态是一种泛型编程思想

即同样的代码,实现不同的功能

父类的指针,调用子类的函数

虚函数是实现这个思想的语法基础

父类指针指向子类空间

CFather* p = new CSon;

但是不能调用子类的函数

形式

virtual void fun() ;

子类的函数 要和这个函数一样

多个子类,换子类就调用子类的

多态针对于指针对象

多态

即父类的一个指针,可以有多种执行状态,即多态

逻辑

问问题

快速检索到面试官想问什么?

多态

子类重写父类的虚函数

内涵和外延

多态是什么?为什么要用多态?怎么样使用多态

内涵

虚函数表 虚函数指针 内存分布 多态的逆向表现 多态汇编

外延

特点

重写

父类和子类相同,父类是虚函数。叫做重写

虚 针对于 函数成员

子类重写的函数,默认是虚函数,可以显示加virtual,也可以不加

名字参数相同

返回值类型相同

重写

返回值类型不同(只能是当前所在类)

协变

不是内联函数

构造函数不能是虚函数

虚表

虚函数覆盖原理

1、根据父类的指针,找到父类的函数

2、看父类的这个show是不是虚函数

进入到虚表,执行表中这个(自己/重写)

不是

执行自己

CFather* p = new CSon; p->show();

取虚表地址,以及内容

对象空间的最开始四字节内容,就是虚表(虚函数列表)的地址,叫虚指针

(int*)*(int*)p+0 (int*)*(int*)p+1 (int*)*(int*)p+2

取到的是函数地址,想要调用,要转换成对应类型的函数指针

void (*p)(int a) = (void (*)(int))(*((int*)*(int*)p+1))

虚析构

delete哪个类型的指针,就调用谁的析构函数

多态中,如果释放父类指针,只会调用父类的析构函数,所以加了虚析构,就会子类父类都调用了

纯虚函数

纯虚函数

形式

virtual void fun() = 0;

特点

可以没有函数实现

继承这个基类的子类必须实现它,才能定义对象

抽象类

有纯虚函数的就是抽象类

接口类

全是纯虚函数的,叫接口类

可以有构造函数,和成员什么的

3 模板

函数模板

首先通过函数重载,实现同名函数,根据不同的参数类型,进行智能调用

引出函数模板

对比函数重载,函数模板,只需要一个函数就搞定

意义:模板是泛型编程的一种重要思想。stl就是利用模板实现的一个具体实例

模板的写法

template <typename T> void fun(T tt) { cout << tt << endl; }

格式

书写

template <typename T>

template <class T>

可以有多个参数

template <typename T, typename Y>

作用域

仅对下边挨着的代码段有效

具体化

就是将我们的指定的类型,单独处理

template<> void fun<job>(job& j1, job& j2);

要单独写个实现

调用:fun(结构1, 结构2);

调用顺序

原版函数->具体化->模板

实例化

生成指定类型的函数定义

template void fun<job>(job& j1, job& j2);

调用:fun(结构1, 结构2);

没有函数实现

类模板

可以设定默认值

template <typename T, typename Y = char>

只有类模板可以有默认值

必须从右向左连续赋值默认类型,跟函数参数默认值一样

传递的时候会覆盖掉

创建对象传递模板参数列表

类模板,需要在类型后加模板参数列表

CFather<int, char> fp;

有默认值的时候可以不传

但是必须要有<>

CFather<> fp;

CFather<int,char>* pf = new CFather<int ,char>;

除了类之外,热河位置出现CFather 都要加上模板参数列表

类外实现的函数模板的写法

template <class T,class B , class C> void CA<T, B, C>::fun(T a) { }

void CFather<int, char>::Show() { cout << a << endl; }

继承的模板

主要是模板参数列表的传递

直接指定固定的类型

通过子类模板参数列表传递

继承的时候要写

:public CFather<T>

构造函数传递(父类有参数构造)

:CFather<T>

创建对象时候要写

CFather<int, char> fp;

多态模板

子类没模板

CFather<short, char>* pf = new CSon;

子类有模板

CFather<short, char>* pf = new CSon<short, int ,char>;

类型一定要对应上

4 常用的STL

string

vector

list和forward_list

set

map

5 C++新特性

总则:C++新特性可以用传统的C++语法实现,从另外的维度,很直接地把原来复杂的问题简单化

C++11/14/17

关键字及新语法

auto关键字

编译器根据上下文情况,确定auto变量的真正类型

auto作为函数返回值时,只能用于定义函数,不能用于声明函数

nullptr

class Test { public: void TestWork(int index) { std::cout << "TestWork 1" << std::endl; } void TestWork(int * index) { std::cout << "TestWork 2" << std::endl; } }; int main() { Test test; test.TestWork(NULL); test.TestWork(nullptr); }

使用nullptr的时候,我们能调用到正确的函数

for循环语法

int main() { int numbers[] = { 1,2,3,4,5 }; std::cout << "numbers:" << std::endl; for (auto number : numbers) { std::cout << number << std::endl; } }

不仅仅局限于数据,STL容器都同样适用

STL容器

std::array

std::array相对于数组,增加了迭代器等函数

std::forwardlist

std::forward_list为C++新增的线性表,与list区别在于它是单向链表

std::unordered_map

std::map使用的数据结构为二叉树,而std::unordered_map内部是哈希表的实现方式

std::unordered_set

std::unordered_set的数据存储结构也是哈希表的方式结构

多线程

std::thread

std::thread为C++11的线程类,使用方法和boost接口一样,非常方便,同时,C++11的std::thread解决了boost::thread中构成参数限制的问题,得益于C++11的可变参数的设计风格

std::atomic

std::atomic为C++11分装的原子数据类型

从功能上看,简单地说,原子数据类型不会发生数据竞争,能直接用在多线程中而不必我们用户对其进行添加互斥资源锁的类型。从实现上,大家可以理解为这些原子类型内部自己加了锁

std::condition_variable

C++11中的std::condition_variable就像Linux下使用pthread_cond_wait和pthread_cond_signal一样,可以让线程休眠,直到别唤醒,现在在从新执行。线程等待在多线程编程中使用非常频繁,经常需要等待一些异步执行的条件的返回结果

智能指针与内存管理

智能指针

智能指针只是用对象去管理一个资源指针,同时用一个计数器计算当前指针引用对象的个数,当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,计数器为1,此时在销毁指针管理对象的同时,也把指针管理对象所管理的指针进行delete操作

std::shared_ptr

std::shared_ptr包装了new操作符动态分别的内存,可以自由拷贝复制,基本上是使用最多的一个智能指针类型

include <memory> class Test { public: Test() { std::cout << "Test()" << std::endl; } ~Test() { std::cout << "~Test()" << std::endl; } }; int main() { std::shared_ptr<Test> p1 = std::make_shared<Test>(); std::cout << "1 ref:" << p1.use_count() << std::endl; { std::shared_ptr<Test> p2 = p1; std::cout << "2 ref:" << p1.use_count() << std::endl; } std::cout << "3 ref:" << p1.use_count() << std::endl; return 0; }

std::weak_ptr

为了解决std::shared_ptr在相互引用的情况下出现的问题而存在的

其他

std::function、std::bind封装可执行对象

std::bind和std::function也是从boost中移植进来的C++新标准,这两个语法使得封装可执行对象变得简单而易用

lamda表达式

在众多的C++11新特性中,lamda表达式不仅仅是一个语法新特性,C++11的lamda表达式在一定程度上还冲击着对传统C++编程的思维和想法

示例

int main() { auto add= [](int a, int b)->int{ return a + b; }; int ret = add(1,2); std::cout << "ret:" << ret << std::endl; return 0; }

[]:中括号用于控制main函数与内,lamda表达式之前的变量在lamda表达式中的访问形式

->int:lamda表达式函数的返回值定义

{}:大括号内为lamda表达式的函数体

运行结果

6 C++对象模型

2、操作系统原理和实战(4-6周)

1 Linux系统命令

常用命令

实用的命令

ifconfig

ping

telnet

iostat

tcpdump

ps

lsof

netstat

free

2 操作系统结构

用户态和内核态的基本概念、区别

3 Linux内存原理

分页内存管理

物理内存和虚拟内存

内存问题分析与性能优化

Linux内存管理

4 进程和线程

进程和线程的概念和区别

进程间通信方式

信号

信号量

共享内存

消息队列

套接字

管道

线程同步

互斥量

信号量

死锁以及产生的原因及解除与预防

锁的实现

生产者-消费者问题

5 文件系统和设备管理

文件的存储

文件目录

文件IO

IO控制方式

设备控制器

6 各种池

线程池

连接池

内存池

7 协程

协程的原理

协程的设计和实现

3、网络(4-6周)

1网络原理

1 网络模型分层

物数网传会表应

2 IP

ping的原理

ICMP

3 TCP

TCP三次握手和四次挥手

TCP头部格式

TCP重传

TCP滑动窗口/流量控制、拥塞控制

TCP半连接和全连接队列

TCP粘包

TCP内核参数

4 UDP

UDP的应用场景

UDP的特性

用UDP模拟TCP

5 HTTP和HTTPS

HTTP 特性

HTTP/1.1、HTTP/2、HTTP/3 演变

GET与POST

HTTP的优化

如何避免发送HTTP请求

如何减少 HTTP 响应的数据大小?

如何减少 HTTP 请求次数?

2 网络编程

1 socket编程

TCP

UDP

HTTP

2 select

3 poll

4 epoll

epoll的几个重要函数

epoll的底层实现原理

epoll的源码分析

边缘触发和条件触发

3 网络通信模型

1 IO类型

阻塞型 BIO

异步IO AIO

非阻塞型IO NIO

2 事件处理模型

Reactor

Proactor

4、基本数据结构与算法(4-100周)

1链表/数组

2栈/队列

3 树/图

4 十大排序

堆雪差炮击,统计快归西

5 查找算法

顺序表查找

有序表查找

线性索引查找

二叉排序树

平衡二叉树

B树和B+树

哈希表

6 分治/贪心

7 动态规划

8 力扣刷

300道

5、设计模式(1-2周)

行为型模式

创建者模式

结构型模式

程序员老秦原创,B站搜索程序员老秦

6 数据库和中间件(3-5周)

1 Mysql

数据库基础

数据库技术的发展

1、人工管理阶段

数据无法长期保存、数据不共享、不具有独立性

2、文件系统阶段

数据可以长期保存、共享性差、数冗余大、独立性差

3、数据库系统阶段

能满足多用户多应用共享数据的需求,与文件系统对比,有着明显的优势

数据库系统的组成 (DataBase System)

数据库(数据) + 数据库管理系统 + 数据库管理员(DBA) + 支持数据库系统的硬件和软件

数据模型

是关于描述数据与数据之间的联系、数据一致性约束的概念性工具的集合

=数据结构+数据操作+完整性约束

数据结构:对系统静态特征的描述,包括数据的类型、内容、性质和数据之间的关系

数据操作:对系统动态特征的描述,是对数据库各种对象实例的操作

完整性约束:是完整性规则的集合,它定义了给定数据模型中数据及其联系所具有的制约和依存规则

常见的数据库模型

层次模型

类似于行政关系、家族关系等树状结构,用层次模型对具有一对多的层次联系的部门描述非常自然、直观,容易理解,这是层次数据库的突出优点

1、其结构类似于一棵倒置的树,有且只有一个结点没有双亲结点,这个结点称为根结点

2、除根节点以外的所有其他节点有且只有一个双亲节点(父节点)

3、任何一个给定的记录值只能按其层次路径查看,没有一个子女记录值能够脱离双亲记录值而独立存在

网状模型

用有向图结构表示实体类型及实体间联系的数据结构模型称为网状模型

1、允许有一个以上的节点无双亲

2、网状模型取消了层次模型的不能表示非数状结构的限制,两个或两个以上的结点都可以有多个双亲结点,则此时有向树变成了有向图

关系模型

以二维表来描述数据,每个表中有多个字段列和记录行,每列都有固定的属性(数字、字符、日期等)

关系模型的基本术语

关系

一个二维表就是一个关系

元组

二维表中的一行,即表中的记录

属性

二维表中的一列,用类型和值表示

每个属性取值的变化范围,如性别的域为{男,女}

关系数据库的规范化

关系数据库中的每一个关系多要满足一定的规范。根据满足规范的条件不同,分为5个等级:第一范式(1NF)、第二范式(2NF)......第五范式(5NF)。 NF是Normal Form的缩写。一般满足第三范式的标准即可。

第一范式(1NF):具备不可再分解的原子特性

1、每个属性只可以包含一个值 2、关系中的每个数组必须包含相同数量的值

第二范式(2NF):属性完全依赖于主键

1、满足第二范式必先满足第一范式 2、每一行的数据只能与其中的某一列相关,一行数据只做一件事

第三范式(3NF):属性不依赖于其它非主属性 属性直接依赖于主键

数据不能存在传递关系,即每个属性都跟主键有直接关系而不是间接关系。像:a-->b-->c 属性之间含有这样的关系,是不符合第三范式的。

数据库操作

常见名词/概念

数据库管理员(DBA)

对数据库进行规划、设计、维护和监控等的专业管理人员

数据库管理系统(DBMS)

位于用户与操作之间的一层数据管理软件

数据定义语言(Data Definition Language,DDL)

数据库常用对象

字段

索引

是一个单独的、物理的数据库结构,需要依赖于表而建立。

视图

从一张或多张表中导出的表,是用户查看数据的一种快捷方式

存储过程

是一组为了完成特定功能的SQL语句集合,经编译后以名称的 形式存储在SQL 服务器端的数据库中,由用户通过制定存储过程的名字来执行。

mysql系统数据库

information_schema

用于存储数据库对象相关信息。例如,用户表信息,列信息,权限信息,字符集信息等。

performance_schema

用于存储服务器性能参数

mysql

sys

常见数据库的操作

创建数据库

CREATE DATABASE 数据库名; / CREATE SCHEMA 数据库名;

CREATE DATABASE IF NOT EXISTS 数据库名;

CREATE DATABASE IF NOT EXISTS 数据库名 CHARACTER SET 'utf8' COLLATE 'utf8_bin';

数据库名称命名规范

不能与已有数据库重名

字母、数字、下划线、$、不能以数字开头

名称最长64字符

windows上表名大小写不敏感,linux上大小写敏感,建议表名都用小写

查看数据库

show databases;

show databases like ''xxx%;

选择数据库

use 数据库名字;

修改数据库

只能修改数据库属性,数据库名称不能修改

alter database 数据库名 CHARACTER SET 'utf8' ;

删除数据库

drop database 数据库名 ;

drop database if exists 数据库名 ;

在删除数据库时,在该数据库上的用户是不会被自动删除的

存储引擎及数据类型

查询支持的全部存储引擎

show engines;

查询默认的存储引擎

show variables like 'default_storage_engine';

常见的存储引擎

InnoDB引擎

优点:提供了良好的事务管理、崩溃修复能力和并发控制。

缺点:读写效率稍差,占用的数据空间相对比较大

mysql5.5版本后,将InnoDB作为默认引擎

MyISAM引擎

优点:占用空间小,处理速度快

缺点:不支持事务的完整性和并发性

在mysql的低版本中,曾作为默认的存储引擎

MEMORY引擎

优点:处理速度非常快

缺点:数据容易丢失,生命周期短

MySql数据类型

数字类型

整数

TINYINT

BIT

SMALLINT

MEDIUMINT

INT

BIGINT

浮点数

FLOAT

DOUBLE

DECIMAL

字符串类型

普通的文本字符串类型

CHAR

VARCHAR

可变类型

TEXT

BLOB

特殊类型

SET

ENUM

日期和时间类型

DATE

格式YYYY-MM-DD

TIME

格式 HH:MM:SS

DATETIME

格式 YYYY-MM-DD HH:MM:SS

TIMESTAMP

YEAR

操作数据表

创建数据表

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] 数据表名

CREATE TABLE `tb_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `create_by` bigint(20) DEFAULT NULL COMMENT '创建人', `create_time` datetime DEFAULT NULL COMMENT '创建时间/注册时间', `modify_by` bigint(20) DEFAULT NULL COMMENT '最后更新人', `modify_time` datetime DEFAULT NULL COMMENT '最后更新时间', `account` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, `avatar` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='用户表';

查看表结构

SHOW COLUMNS FROM 数据表名

DESCRIBE / DESC 数据表名

修改表结构

ALTER TABLE 表名 ......

加字段

ADD email varchar(50) not null;

修改字段属性

MODIFY account varchar(50);

修改字段名

CHANGE COLUMN account username varchar(30) default null;

删除字段

DROP account;

修改表名

RENAME AS 新的表名

重命名表

RENAME TABLE 表1 TO 表2

该语句可以对多个表重命名(用逗号隔开): RENAME TABLE 表1 TO 数据表1 , 表2 TO 数据表2;

复制表

CREATE TABLE [IF NOT EXIST] 表名 LIKE 源表名

CREATE TABLE [IF NOT EXIST] 表名 ( LIKE 源表名)

CREATE TABLE [IF NOT EXIST] 表名 AS SELECT * FROM 源表名

复制表的同时也复制了数据

删除表

DROP TABLE [ IF EXISTS] 表名

Mysql基础

运算符

算术运算符

+、-、*、/、%

1/5=0.2000

DIV

1 DIV 5 = 0 4 DIV 2 =2

MOD

求余数,等同于%

比较运算符

=、>、<、>=、<=、!=、<>

IS NULL 、IS NOT NULL

BETWEEN AND

IN 、 NOT IN

LIKE 、 NOT LIKE

REGEXP

经常与“^”,“$”,“.”一起使用,“^”用来匹配字符串开始的部分,$用来匹配字符串结尾部分,.用来代表字符串中的一个字符。

逻辑运算符

&& 或 AND

|| 或 OR

! 或 NOT

XOR(异或)

只要其中任何一个数据为NULL时,结果返回NULL

如果两个操作数都是非0或者都是0 ,则返回0,否则返回1

位运算符

&

按位与

|

按位或

~

按位取反

^

按位异或

<<

按位左移

>>

按位右移

流程控制语句

IF语句

select if(flag=1,'yes','no') from user;

CASE语句

select case flag when 1 then '有效' when 0 then '无效' else 'other' end from user;

while循环语句

一般在存储过程和存储函数中使用

DELIMITER $$ CREATE PROCEDURE test_while_001(IN in_count INT) # 创建存储过程 学习while循环的用法 BEGIN DECLARE COUNT INT DEFAULT 0; DECLARE SUM INT DEFAULT 0; WHILE COUNT < in_count DO SET SUM = SUM + COUNT; SET COUNT = COUNT + 1; END WHILE; SELECT SUM; END $$ DELIMITER ;

LOOP循环语句

LOOP ... END LOOP

REPEAT循环语句

表数据的增、删、改、查操作

插入数据

insert into 表名 values

插入多行记录: insert into user (user,password) values ('xiaobo','123456'),('user2','123456');

insert into user (user,password) values ('xiaobo','123456');

insert into user values ('values1',''value2,'value3')

insert into 表名 set

insert into user set user='user01',password = '123456' ;

插入查询结果 insert into 表名 select xxx from 其他表名

insert into user(username,password) select user,passwd from user01;

修改数据

update 表名 set 字段1 = 值1 where 条件表达式 order by ... limit 行数

删除数据

delete

delete from 表名 set 字段1 = 值1 where 条件表达式 order by ... limit 行数

truncate table

会删除所有数据

1、表中的AUTO_INCREMENT计数器将被重新设置为该列的初始值 2、对于参与了索引和视图的表,不能使用truncate table语句来删除数据 3、truncate 比delete操作使用的系统和事务日志资源少。

查询数据

基本查询语句的语法: select 字段名 from 数据表名 where 查询条件 group by 字段 order by 字段 having ... limit xxx;

like 模糊查询

%

匹配一个或多个字符

_

只匹配一个字符

其他查询用法

is [not] null 判断某个字段是否为空值,加上not则表示不是空值

多条件查询

and

or

distinct

去重重复记录

order by

asc 表示升序,默认升序

desc 表示降序

对于含有NULL值的列排序时,如果按升序,NULL值将出现在最前面,按降序的话,NULL值会出现在最后面

group by

使用group by时,select的字段只能是group by后面的字段、以及包含在聚合函数中的字段

如何在不使用聚合函数的情况下,select 非group 的字段 ? 可以临时修改@@sql_mode的值 。 先使用select @@sql_mode ; 查看结果 ,发现其中会有一个ONLY_FULL_GROUP_BY ,将这个枚举值去掉即可 。 可以临时使用 set @@sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' 修改配置

使用group by 时,where将对分组前的所有数据进行筛选。having将对分组后的一组数据进行过滤。

聚合函数查询

根据一组数据求出一个值,聚合函数值根据选定的非NULL值进行计算,NULL会被忽略

count()函数

统计有多少行

sum()函数

求和函数

avg()函数

求平均值

max() 、min()函数

求最大 最小值

连接查询

把不同的表记录连接到一起进行查询

内连接查询

inner join 返回两表的交集

语句: select 表1查询的字段,表2查询的字段 from 表1 inner join 表2 on 条件; select a.*,b.* from course as a inner join rollcall as b on a.course_id=b.course_id;

外连接

左外连接 left join 是left outer join的简写

左表(a_table)的记录将会全部表示出来,而右表(b_table)只会显示符合搜索条件的记录。右表记录不足的地方均为NULL

右外连接 right join是right outer join的简写

左表(a_table)只会显示符合搜索条件的记录,而右表(b_table)的记录将会全部表示出来。左表记录不足的地方均为NULL

子查询

带关键字in的子查询

select * from tb_login where user in (select user from tb_book);

带比较运算符的子查询

select id ,books,row from tb_book where row >= (select row from tb_row where id =1);

带exists的子查询

select * from tb_row where exists (select * from tb_book where id =27); --如果不存在id为27的数据,就不执行外面的查询

带关键字any的子查询

select *from user where id >any (select id from tb_id where id > 3 );

满足any后面查询语句返回结果中的任何一个结果,就会执行外层查询语句

带关键字all的子查询

select *from user where id >all(select id from tb_id where id > 3 );

需要满足all后面查询语句中返回的每一个查询结果,才会执行才层查询语句

合并查询结果

union

会对数据进行去重

union all

不会对数据进行去重,只会将不同表的数据合并到一起

查询案例: select user from tb_user1 union select user from tb_user2

使用正则表达式查询

使用某种模式去匹配一类字符串的一种方式,比使用通配符的查询更强大 ,更灵活

常见使用案例

^

匹配以特性字符或字符串开头的记录

select books from tb_book where book_name REGEXP '^python'

$

匹配以特定字符或字符串结尾的记录

select books from tb_book where book_name REGEXP 'python$'

.

匹配字符串的任意一个字符,包括回车和换行符

select books from tb_book where book_name REGEXP 'P.' (查找包含字符P的记录)

[字符集合]

匹配“字符集合”中的任意一个字符

select books from tb_book where book_name REGEXP '[ABC]' (匹配字段中包含ABC中任意一个字符的记录)

[^字符集合]

匹配除“字符集合”以外的任意一个字符

S1|S2|S3

匹配S1、S2、S3中的任意一个字符串

*

匹配多个该符号之前的字符,包括0个和1个

select books from tb_book where book_name regexp 'J*A' (匹配在A字符前出现过J字符的记录,出现过0次也会统计)

+

匹配多个该符号之前的字符,至少出现过一次

字符串{N}

匹配字符串连续出现N次

select book from tb_book where book_name regexp 'a{3}' (匹配该字段连续出现3次a字符的记录)

字符串{M,N}

匹配字符串至少连续出现M次,最多出现N次

常用函数

数学函数

abs(x) 绝对值函数

ceil(x) 返回不小于x的最小整数值,及向上取整

floor(x) 返回不大于x的最大整数值,及向下取整

rand() 返回0~1随机数

rand(x) 返回0~1随机数,x值相同时,返回的随机数相同

truncate(x,y) 返回数值x保留y位小数的结果,直接截取小数位

round(x) 返回离x最近的整数

round(x,y) 返回x小数位后y位的值,但截断的时候要进行四舍五入

字符串函数

char_length(x) 返回字符长度

length(x) 返回字节长度

concat(s1,s2,...) 字符串拼接,如果有一个参数为NULL,则返回NULL

CONCAT_WS(separator,str1,str2,…) 第一个参数是其它参数的分隔符。分隔符的位置放在要连接的两个字符串之间。分隔符可以是一个字符串,也可以是其它参数。如果分隔符为 NULL,则结果为 NULL

... 字符串函数有很多,暂时不一一列举

日期和时间函数

CURDATE(),CURRENT_DATE() 返回当前日期 CURTIME(),CURRENT_TIME() 返回当前时间 NOW(),CURRENT_TIMESTAMP(),LOCALTIME(),SYSDATE(),LOCALTIMESTAMP() 返回当前日期和时间

UNIX_TIMESTAMP() 日期转时间戳 FROM_UNIXTIME() 时间戳转日期

条件判断函数

系统信息函数

加密函数

其他函数

子主题 8

程序员老秦原创,B站搜索程序员老秦

2 Redis

1常用五大数据类型

1、键(key)操作

2、Redis字符串(String)

3、Redis列表(List)

4、Redis集合(Set)

5、Redis哈希(Hash)

6、Redis有序集合Zset

2 Redis的发布和订阅

1、什么是发布和订阅

2、Redis的发布和订阅

3、发布订阅命令行实现

3 Redis的事务操作

1、Redis的事务定义

2、事务操作Multi、Exec、discard

3、事务的错误处理

4、事务冲突的问题(乐观锁和悲观锁)

5、Redis事务三特性

4 Redis持久化

AOF

RDB

5 Redis集群

6 Redis源码阅读

3 Nginx

4 ZeroMQ

5 MongoDB

程序员老秦原创,B站搜索程序员老秦

7 调试和测试(2-4周)

1 GDB

基本的GDB调试命令

调试dump

调试多线程

调试多进程

调试大型源码

2 安全

MD5

程序员老秦原创,B站搜索程序员老秦

加密库 OpenSSL

3 日志

日志的设计、实现与测试

4 服务器调试与测试

性能测试

测试的设计

调整内核参数

稳定性测试和压力测试

5 单元测试

8 工具(1-2周)

浏览器

chrome

IDE

VS2019/2022或者VSCODE

代码比对工具

beyond compare

计划类

127天

笔记类

蚂蚁笔记

有道云笔记

文件管理类

everything

代码检测工具

CPPCheck

9 项目(6-8周)

最好是包含以上全部知识点的项目

1、熟练掌握商用级项目的设计与实现; 2、理解分布式架构,服务器集群设计; 3、掌握大型后台程序的开发与实现、掌握多线程、多进程编程; 4、完成端口映射和异步通信模型实战; 5、掌握常用的网络通信协议以及数据解析协议; 6、掌握日志系统的设计与实现; 7、非对称加密解密; 8、UML(类图、时序图、状态图)、数据流图、E-R实体关系图、ORM(对象关系映射)实现 9、gtest单元测试和svn/git版本控制

10 其他知识(2-4周)

设计文档

工程架构

cmake

Makefile

代码管理

git

svn

相关思维导图模板

项目研究路线思维导图

树图思维导图提供 项目研究路线 在线思维导图免费制作,点击“编辑”按钮,可对 项目研究路线  进行在线思维导图编辑,本思维导图属于思维导图模板主题,文件编号是:9feb100f005d8ce7cb917cb1067eaed7

3~6岁儿童学习与发展指南()思维导图

树图思维导图提供 3~6岁儿童学习与发展指南() 在线思维导图免费制作,点击“编辑”按钮,可对 3~6岁儿童学习与发展指南()  进行在线思维导图编辑,本思维导图属于思维导图模板主题,文件编号是:68be5ab8a99d2de892152a3274eff403