TreeMind树图在线AI思维导图
当前位置:树图思维导图模板IT互联网互联网干货c++知识点全概括脑图思维导图

c++知识点全概括脑图思维导图

  收藏
  分享
免费下载
免费使用文件
U745380960 浏览量:382023-09-17 00:57:40
已被使用4次
查看详情c++知识点全概括脑图思维导图

C++编程语言全内容知识点分解

树图思维导图提供 c++知识点全概括脑图 在线思维导图免费制作,点击“编辑”按钮,可对 c++知识点全概括脑图  进行在线思维导图编辑,本思维导图属于思维导图模板主题,文件编号是:c7c2c128bef9d0fdcc40d8798f1d868f

思维导图大纲

c++知识点全概括思维导图模板大纲

作者信息

作者:胖胖秦

C/C++语法知识点的预习和复习

网盘链接:https://pan.baidu.com/s/135NoMRRz4dqXoDGtCVmdBA 提取码:1111

参考书籍

C++ primer plus(第六版) 935

软件

vs2019

喜欢哪个用哪个

基础知识点

程序员的第一个程序

#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 内存

类型转换

隐是类型转换

显示类型转换

强制类型转换

其他

类型修饰符

auto

自动变量

通常的局部变量

static

静态变量

const

注意修饰的位置

extern

预处理

#define

替换

参数宏

链接/,#,##

包含头文件

#include

“” 与 <>的区别

防止头文件重复包含

#ifndef AAA #define AAA #endif

通用

#pragma once

取决于编译器,移植性不好

好写

多文件

理论

类和面向对象的关系

面向对象是一种编程思想

类是一个语法

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

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

学习

编程学到什么程度

基础熟练

会拓展

学习编程重实践

尽量手撸代码

类实例

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;

特点

可以没有函数实现

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

抽象类

有纯虚函数的就是抽象类

接口类

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

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

虚继承

多继承

多个基类

子类的子类

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

父类叫做虚基类

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

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

其他

联编

联编

就是将模块或者函数合并在一起生成可执行代码的处理过程,(函数调用),按照联编所进行的阶段不同,可分为两种不同的联编方法:静态联编和动态联编。

静态联编

指在编译阶段就将函数实现和函数调用关联起来

例子

普通的函数调用

动态联编

是指在程序执行的时候才将函数实现和函数调用关联

举个例子

CFather* p; cin >> index; switch(index) { case 1: p = new CFather; break; case 2: p = new CSon; break; } p->show();

动态联编是针对c++的多态的,C语言里全部是静态联编

单例

一个类只能创建一个对象

关键点

1、构造函数

private/protected

不能实例化对象

2、通过静态成员函数申请对象空间,并返回地址

3、定义一个静态标记,记录对象的个数,并控制

4、析构函数,将标记清空,以达到重复申请对象的目的

不能被继承的类

private

不能继承

运行报错

异常

异常是人为定义的一种状况

abort()

异常中止

try throw catch

try { show();//函数调用 } catch(参数) { } catch(参数) { } show() { throw(12); }

抛出对象的时候,要用引用或者指针,不然会拷贝备份出来,即拷贝构造函数

类型转换

旧式类型转换

(type)value

(double)12;

type(value)

新式类型转换

static_cast

当type和expression可以互相隐式转换的时候, 这个方法执行起来才是合法的

如:基类子类之间互相转化没问题,如果跟一个不相干的类进行转换,就报错了

形式

static_cast <type> (expression)

例子

CFather* pf; CSon* so; COther* ot; so = static_cast <CSon*> (pf) ; pf = static_cast <CFather*> (so) ; ot = static_cast <COther*> (so) ; //非法

const_cast

类型转换掉表达式的const或volatile属性,仅当type和expression一样的时候,才合法

注意:转指针与转非指针,非指针要传地址或者引用

形式

const_cast <type> (expression)

例子

const CFather* pf; CSon* so = const_cast <CSon*> (pf) ; //非法 CFather* pfff = static_cast <CFather*> (pf) ; //合法

dynamic_cast

特点

e的类型是目标type的共有派生类

e的类型是目标type类型

e的类型是目标type的共有基类

多态的情况

父子类指针相互转化的运算符,或者自己转自己

格式

dynamic_cast <type> (expression)

CFather* pf = dynamic_cast<CFather*>son;

reinterpret_cast

运算符用于天生危险的类型转换

形式

reinterpret_cast <type> (expression)

例子

struct dat { short a; short b; }; long value = 0xA224B118; dat* p = reinterpret_cast<dat*>(&value); cout << hex << p->a;

注意点

这种转换适用于依赖实现的底层编程技术,代码不可移植。例如不同的系统可能以不同的顺序存储多字节数据中的字节

互相转换时,空间一定要够用,否则不行

函数指针和数据指针不能相互转换

运算符重载

作用

赋予运算符自定义功能

默认

常数+常数

比如对象+对象,默认情况下是不被允许的,当我们重载了+,后,就可以实现对象相加了

对象+常数,常数+对象

重载函数,函数的两个参数,在小括号内,运算符的两个参数在两侧

形式

返回值 operator+运算符(参数列表)

返回值的作用

连续运算

重载+

先用这个 + 做例子进行讲解

类型

类外

左边是左参数,右边是右参数

类内

默认左边是类的类型

固定的,所以,固定

注意点

1、有的运算符可以重载,有的不可以

必须是C++有效运算符 C++ primer (第五版)

运算符重载表

@不是运算符,不能重载这个

2、是类的成员,或者包含一个类的参数

3、明智使用,避免滥用

4、类内还是类外(c++ primer 第五版,493页)

(1)、根据实际情况,左操作数不是对象的,就选择类外重载运算符

(2)、=, [ ], ( ), ->必须是成员

(3)、复合赋值运算符通常是成员

+= <<=

(4)、改变对象状态的运算符, 如递增递减和解引用,通常是成员

(5)、算术,关系,位运算,非成员

做几个重载的例子

什么事一元,什么是2元

一个操作数一元运算符

两个操作数二元运算符

三个操作数三元运算符

什么事操作数

参数

二元运算符

算术运算符

+ ,- ,* ,/ ,% ,

关系运算符

>= ,<= ,> ,< ,!= ,==

位运算符

^ ,& ,I

逻辑运算符

&&,||

一元运算符

+,-,&,*,

正,负,取地址,内存操作符

~, !

输入输出 << >>

ostream

cout是一个对象

istream

cin是一个对象

<<

ostream& operator<<(ostream& os, const CStu&st){ return os;}

参数1是ostream引用,参数2是对象的常引用

返回值保证连续输出

必须是类外,可想而知

类友元

>>

istream& operator>>(istream& is, CStu& st){return is;}

需要输入检测是否失败

赋值

=

必须类内,否则报错

符合赋值运算符

+=, -+, *=, /=,%=, <<=, >>= , ^=,&=, |=

建议类内,类外也行

下标运算符

[ ]

返回引用

只能类内

递增递减运算符

前置运算符

左++

类内无参数

类外一个参数

左--

同上

后置运算符

右++

类内一个参数 int n

两个参数,(对象, int n); n可用可不用,可以说是作为右加加的一个标记

右--

同上

重载类型转换

特点

1、没有显示返回类型

但是要写返回值

2、没有参数

3、必须定义成类的成员函数

4、不应该改变对象的内容,所以是const函数

5、避免过度使用

什么时候用?

模板

函数模板

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

引出函数模板

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

意义:模板是泛型编程的一种重要思想。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>;

类型一定要对应上

模板类型是类的模板

CAA<char> aa('b'); CSon<int, CAA<char>> son(100, aa);

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表达式的函数体

运行结果

总结

对于初学者

1、对整个C/C++知识点做一个概览,知道要学习什么,什么是重点

2、不是劝退!不是劝退!不是劝退!知识点看起来很多,实际上学习时间为6到8周;

3、学完了一遍甚至2遍忘记很正常,不忘记才不正常

4、一定是一边学习一边敲代码

5、便于系统性的学习

对于老手

1、知识的查漏补缺,要用什么就查什么

2、总结一些面试或者笔试的常见考点

3、最好是自己花个一个小时,回忆一遍,到底自己哪些知识点有欠缺,再加深印象

相关思维导图模板

抓住重点思维导图

树图思维导图提供 抓住重点 在线思维导图免费制作,点击“编辑”按钮,可对 抓住重点  进行在线思维导图编辑,本思维导图属于思维导图模板主题,文件编号是:4c49e4799ddf94a339c56e46eb96a826

主机安全防御思维导图

树图思维导图提供 主机安全防御 在线思维导图免费制作,点击“编辑”按钮,可对 主机安全防御  进行在线思维导图编辑,本思维导图属于思维导图模板主题,文件编号是:fa34d4fe2f232e3cb5713f4995d45a66