C++核心编程
C++面向对象
1.内存分区模型
C++程序执行时会将内存大方向分为__4个区域__
- 代码区:存放函数体的二进制代码,由操作系统管理
- 全局区:存放全局变量、静态变量和常量
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
- 堆区:由程序员分配和释放,若不释放则程序结束时由系统回收
什么是堆:堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。
什么是栈:栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。
1.1程序运行前
在程序编译后,生成了exe可执行程序,在未执行程序前就已经分为两个区域
__代码区:__存放CPU执行的机器指令
- 代码区是共享的,目的是对于被频繁执行的程序,只需要在内存中复制一份代码
- 代码区是只读的,防止程序意外修改了其指令
__全局区:__存放全局变量、静态变量和常量
- 全局区包含了常量区,字符串常量和其他常量也存放在此,但const修饰的局部变量(即局部常量)不在此区域存放
- 该区域数据在程序结束后由系统释放
2.2程序运行时
**栈区:**由编译器自动分配释放,存放函数的参数值,局部变量等
注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
例:
int* func()
{
int a = 10;
return &a; //错误
}
**堆区:**由程序员分配释放,未释放的在程序结束时由系统回收
使用内存分配与释放关键字new
/delete
管理内存
2.3new/delete关键字
语法:new 数据类型(初始化值);
,初始化赋值可以没有,返回值为该数据类型的指针
new 数据类型[数组元素个数];
,为数组开辟连续空间,返回值为连续空间的首地址
delete 指针;
,将指针指向的内存空间释放
delete[] 数组指针;
,将指针指向的数组空间释放
2.引用
https://www.cnblogs.com/mlgjb/p/8821340.html
引用的本质在c++内部实现是一个指针常量
2.1引用的基本使用
作用:给变量起别名
语法:数据类型 &别名 = 变量名
**注意:**引用定义时必须同时初始化,引用后名称不能修改
2.2引用作函数参数
效果等同于地址传递,减少了传值过程中的内存占用,比使用指针可读性高
void Swap(int &a , int &b) //用引用的方式接受参数
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10 , b = 20;
Swap(a , b); //正常传入参数,注意不能直接传入常量
}
2.3引用作函数返回值
语法:定义函数时在函数名前加&
注意:
- 不要返回局部变量的引用
- 函数的调用可以作为左值(等效于对函数返回的变量赋值)
2.4常量引用
作用:主要用来修饰形参,防止误操作
用法:用const修饰函数形参
void test(const int& x)
{
cout << x <<endl;
}
int main()
{
test( 10 ); //编译器先定义临时变量值为10,再将临时变量传入,只有在const修饰形参时有效
}
3.进阶函数
3.1函数默认参数
在调用函数但未传入参数时,函数形参使用默认参数。默认参数在函数定义时定义
语法:返回值类型 函数名(参数 = 默认值) {函数体}
注意:
- 有默认值的参数定义时需要放在最右边,即有默认值的参数右边都必须有默认值
- 如果函数声明时规定了默认参数,则函数实现不能再规定默认参数
例:
void main()
{
int func(int a, int b = 2; int c = 3); //有默认参数的参数后面全部有默认参数
cout << func(10 , 20 , 30) <<endl;
}
int func(int a, int b, int c) //函数实现中不能再次规定默认参数
{
return a + b + c;
}
3.2函数占位参数
语法:返回值类型 函数名(数据类型){函数体}
当定义了占位参数时,调用函数必须传入相应数据类型的参数,除非定义带默认值的占位参数
例:
void func(int a, int, int = 10) //三个参数分别为普通参数,占位参数,带默认值的占位参数
{
return a;
}
3.3函数重载
条件:
- 在同一作用域中
- 函数名相同
- 传入参数的类型,数量,顺序不同(数据类型的数量和顺序)
- **注意:**返回值类型不同不能作为函数重载的条件
函数重载注意事项:
- 引用作为重载条件
void func(int &a)
{
cout << "func(int &a) used" <<endl;
}
void func(const int &a)
{
cout << "func(const int &a) used" <<endl;
}
int main()
{
int var = 10;
func( var ); //调用func(int &a)
func( 10 ); //调用func(const int &a)
return 0;
}
- 函数重载遇到函数默认参数
void func(int a, int b = 10)
{
cout << "func(int a, int b = 10) used" <<endl;
}
void func(int a)
{
cout << "func(int a) used" <<endl;
}
int main()
{
func( 10 ); //当除去默认参数后两个函数的参数相同时,函数重载出错
func(10, 20); //正确
return 0;
}