施磊C++初级笔记

image-20230321143438563

1 深入学习C++语言先要练好的内功

1.1 掌握进程虚拟地址空间区域划分

image-20230320221443055

image-20230320221901794

1.2 从指令角度掌握函数调用堆栈详细过程

image-20230321111119551

image-20230321112224556

具体得看视频,讲述了main函数调用sum方法每步的空间变化。

1.3 从编译器角度理解C++代码的编译和链接原理

image-20230321142611763

image-20230321142632348

2 C++基础

2.1 深入理解new,delete

malloc和free称作C的库函数,new和delete称作运算符;

new不仅可以做内存开辟,还可以做内存初始化操作;

malloc开辟内存失败,是通过返回值和nullptr作比较;而new开辟内存失败,是通过抛出bad_alloc类型的异常来判断;

1
2
3
4
5
6
7
8
9
// new有多少种?
int *p1 = new int(20);
int *p2 = new (nothrow) int;
const int *p3 = new const int(40);

// 定位new
int data = 0;
// 在一块已经定位好内存的内存块上,初始化值为50
int *p4 = new (&data) int(50);

2.2 C++的const

const怎么理解?

const修饰的变量不能再作为左值!!!初始化完成后值不能被修改!!!

C和C++中的区别是什么?

C中const修饰的量不叫常量,叫常变量 ;

C++中const必须初始化,叫常量;

C++中若

1
2
int b = 20;
const int a = b;

此时a已经被修改了,就是常变量而不是常量了,因为其初始值不是一个立即数。

const编译方式不同,C中const当作一个变量来编译生成指令的;C++中,所有出现const常量名字的地方都会被常量的初始值替换;

2.3 const和一二(多)级指针的结合应用

const修饰的量常出现的错误

1.常量不能再作为左值;(直接修改)

2.不能把常量的地址泄露给一个普通的指针或者普通的引用变量;(如下做了间接修改)

1
2
3
const int a = 10;

int *p = &a; // int* <= const int* xxx!!!

const和一级指针的结合

1
2
3
4
const int *p;	// p指针可以指向任意int类型的内存,但无法通过指针间接修改指向的内存的值(离const最近的类型为int)
int const* p; // 同上
int *const p; // 这个指针p现在是常量,不能再指向其他内存,但可以通过指针解引用修改指向的内存的值(离const最近的类型为int*)
const int *const p; // 指针p是常量,其指向内存的值也无法修改

C++的语言规范:const修饰的使离它最近的类型

const和一级指针的结合有两种情况:

一种是使指针是常量,无法再指向其他内存;一种是使指针指向的内存的值是常量,无法在被修改。

总结,const和指针的类型转换公式:

int <= const int 是错误的!**

const int <= int 是可以的!**

int** <= const int**是错误的!

const int** <= int**是错误的!

const如果右边没有指针*的话,const是不参与类型的。

const和二级指针的结合

1
2
3
const int **q;	// **q不能被赋值
int *const* q; // *q不能被赋值
int **const q; // q不能被赋值

2.4 C++的引用

引用和指针的区别?

引用是一种更安全的指针。

1.引用是必须初始化的,指针可以不初始化;

2.引用只有一级引用,不存在多级引用;指针可以有一级指针,也可以有多级指针;

3.定义一个引用变量和定义一个指针变量其汇编指令是一模一样的;通过引用变量修改所引用内存的值,和通过指针解引用修改指针指向内存的值,其底层指令也是一模一样的;

右值引用

1.int &&c = 20; 专门用来引用右值类型,指令上,可以自动产生临时量,然后直接引用临时量 c = 40;

2.右值引用变量本身是一个左值,只能用左值引用来引用它;

3.不能用一个右值引用变量来引用一个左值;

1
2
3
4
5
6
7
8
int array[5] = {};
int *p = array;
// 定义一个引用变量,来引用array数组
int (&q)[5] = array;
cout << sizeof(array) << endl;
cout << sizeof(p) << endl;
cout << sizeof(q) << endl;
// 20 4 20
1
2
3
4
5
6
7
8
9
10
11
12
int a = 10;	// 左值,它有内存,有名字,值可以修改
int &b = a;

// int &c = 2-; // 20是右值:没内存,没名字
// C++提供了右值引用 一个右值引用变量本身是一个左值
int &&c = 20;
c = 30;
/*
int tmp = 20;
tmp -> d
*/
const int &d = 20;

const、一级指针、引用的结合

1
2
3
4
5
6
7
8
// 写一句代码,在内存0x0018ff44处写一个4字节的10
// 引用一个int常量
int *const &p = (int*)0x0018ff44;

int a = 10;
int *p = &a;
// q是a的引用变量
int *&q = p;

2.5 函数重载

什么是函数重载

1.一组函数,其中函数名相同,参数列表的个数或者类型不同,那么这一组函数就称作函数重载;

2.一组函数要称得上重载,一定先是处在同一个作用域当中的;

3.const或者volatile,是怎么影响形参类型的;

4.一组函数,函数名相同,参数列表也相同,仅仅是返回值不同不叫重载;

请解释一下多态?

静态(编译时期)的多态:函数重载

动态(运行时期)的多态:

C++为什么支持函数重载,C语言不支持函数重载?

C++代码产生函数符号的时候,函数名+参数列表类型组成的!

C代码产生函数符号,函数名来决定!

2.6 inline函数

inline内联函数和普通函数的区别

inline函数:在编译过程中,就没有函数的调用开销了,在函数的调用点直接把函数的代码进行展开处理了

inline函数不再生成相应的函数符号

inline只是建议编译器把这个函数处理成内联函数,但是不是所有的inline都会被编译器处理成内联函数——递归

debug版本上,inline是不起作用的;inline只有在release版本下才能出现

g++ -c main.cpp -02 objdump -t main.o

3 C++面向对象

3.1 this指针

this指针 => 类 => 很多对象 共享一套成员方法

成员方法,方法的参数都会添加一个this指针

构造函数:定义对象时,自动调用的;可以重载的;构造完成,对象产生了

析构函数:不带参数,不能重载,只有一个析构函数;析构完成,对象就不存在了

OOP语言的四大特征是?

抽象 封装/隐藏 继承 多态

3.2 对象的深拷贝和浅拷贝

对象默认的拷贝构造是做内存的数据拷贝

关键是对象如果占用外部资源,那么浅拷贝就出现问题了!(占用同一个资源析构两次就会出错!)

此时(对象的浅拷贝出现问题了)就需要自定义拷贝构造函数赋值函数(运算符重载)

3.3 构造函数的初始化列表

初始化列表做初始化和在函数体内初始化区别?

int amount = 0;和 int amount; amount = 0;的区别,若数据类型为自定义类型,未指定该自定义类型的构造函数(调用默认构造函数),则无法成功构造。