目录
主要针对面向对象编程技巧
面向对象程序设计:以类为基本单位组织编写程序
面向过程程序设计:以函数/过程为基本单位组织编写程序
1.1内存分区模型
内存分为4个区域:
- 代码区:存放函数体的二进制代码
- 全局区:存放全局变量和静态变量以及常量
- 栈区:由编译器自动分配释放
- 堆区:由程序员自动分配释放,若程序员不释放,则程序结束后由操作系统收回
1.1.1程序运行前
代码区:存放CPU执行的机器指令(二进制代码)
(特点)代码区是共享的,目的是对于频繁被执行的程序,内存中只有一份代码。
代码区是只读的,目的是防止程序意外被修改了它的指令。
全局区:(特点)该区域的数据在程序运行完后由操作系统释放
#include<iostream>
using namespace std;
//全局变量(g--global)
int g_a = 10;
int g_b = 10;
//const修饰的全局变量
const int c_g_a = 10;
const int c_g_b = 10;
int main()
{
//局部变量
int a = 10;
int b = 10;
cout << "局部变量a的地址为:" << (int)&a << endl;//强制转换成十进制
cout << "局部变量b的地址为:" << (int)&b << endl;
//全局变量
cout << "全局变量a的地址为:" << (int)&g_a << endl;
cout << "全局变量b的地址为:" << (int)&g_b << endl;
//静态变量(s--static)
static int s_a = 10;
static int s_b = 10;
cout << "静态变量a的地址为:" << (int)&s_a << endl;
cout << "静态变量b的地址为:" << (int)&s_b << endl;
//常量
//字符串常量
cout << "字符串常量的地址为:"<< (int)&"hello word" << endl;
//const修饰的常量
//const修饰的全局变量(全局常量)
cout << "全局常量a的地址为:" << (int)&c_g_a << endl;
cout << "全局常量b的地址为:" << (int)&c_g_b << endl;
//const修饰的局部变量(局部常量)
const int c_a = 10;
const int c_b = 10;
cout << "局部常量a的地址为:" << (int)&c_a << endl;
cout << "局部常量b的地址为:" << (int)&c_b << endl;
system("pause");
return 0;
}
在一个函数体内就叫局部变量,在一个函数体外就叫全局变量
由上述代码可知:局部常量(const修饰的局部变量)和局部变量不属于全局区;
全局变量、静态变量、常量(字符串常量、全局常量)属于全局区。
1.1.2程序运行后
栈区:由编译器自动分配和释放
注意:不要返回局部变量的地址
#include<iostream>
using namespace std;
int * fun()//形参数据也会存放在栈区
{
int a = 10;
return &a;
}
int main()
{
int *p = fun();
cout << *p<< endl;
cout << *p << endl;
system("pause");
return 0;
}
代码运行如下:

可以发现两个一样的代码,输出的*p的值却不一样,这是为什么?
栈区的数据在程序执行完后就会自动释放,第一次还会打印正确的是因为编译器做了保留。
堆区:由程序员分配释放,程序结束时由操作系统回收
利用new可以将数据开辟到堆区
#include<iostream>
using namespace std;
int * fun()
{
//指针的本质还是局部变量,放在栈上,指针保存的数据是放在堆区上的
int *p= new int(10);//new可以创建堆区数据,返回的是堆区数据的地址
return p;
}
int main()
{
int *p = fun();
cout << *p<< endl;
cout << *p << endl;
system("pause");
return 0;
}
代码运行如下:

1.1.3new操作符
new一个数据,则会返回该数据类型的地址,如果想释放堆区的数据,需要利用关键字delete。
如修改如下:
int main()
{
int *p = fun();
cout << *p<< endl;
cout << *p << endl;
delete p;
cout << *p << endl;//该数据已被释放,若再访问则会报错。
system("pause");
return 0;
}
堆区开辟数组:
释放数组需要加[]
#include<iostream>
using namespace std;
int main()
{
int *arr = new int[10];
for (int i = 0; i < 10; i++)
{
arr[i] = i + 100;
}
for (int i = 0; i < 10; i++)
{
cout << arr[i] << endl;
}
delete[]arr;
system("pause");
return 0;
}
1.2引用
用途:给变量起别名
语法:数据类型 &别名=原名
int main()
{
int a = 10;
int &b = a;
cout << a << " " << b << endl;
b = 100;
cout << a << " " << b << endl;
system("pause");
return 0;
}
代码运行如下:

注意:
- 引用必须要初始化//eg:int &b;---错 引用必须上来就说明是谁的别名
- 引用初始化后面就不可以改变了//eg:b一开始为a的别名,现在又改为c的别名---错 一旦初始化后就不可以更改了
传参时,可以利用引用让形参修饰实参
#include<iostream>
using namespace std;
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
swap(a, b);
cout << a << " " << b << endl;
system("pause");
return 0;
}
代码运行发现a,b发生了交换,所以引用传递形参改变实参也会发生改变。
注意:
- 不能返回局部变量的引用//第一次输出正确是因为编译器做了保留,但之后就会输出乱码
- 如果函数的返回值是引用,则函数调用可以写在等号左边
int& text()
{
int a = 10;
return a;
}
int& text1()
{
static int a = 10;
return a;
}
int main()
{
int &n = text();
cout << n << endl;
cout << n << endl;
cout << n << endl;
int &x = text1();
cout << x << endl;
cout << x << endl;
text1() = 20;
cout << x << endl;
cout << x << endl;
system("pause");
return 0;
}
引用的本质:在c++内部实现是一个指针常量
如下:

常量引用
作用:主要用来修饰形参,防止误操作(引用修饰后,形参改变了实参就会改变)
eg:int &ref=10;//错 引用需要一个合法的存储空间
const int&ref=10;//加上const之后,编译器将代码修改为int temp=10;int &ref=temp并且ref是不可以修改的
1.3函数提高
1.3.1函数默认参数
语法:返回值类型 函数名(参数=默认值){}
要是我们自己传入参数就用我们自己传入的,要是没有传就用默认的。
注意:1、如果某个位置有默认值,则从这个位置开始往右都要有默认值。
2、函数的声明和实现只能有一个含默认参数。
#include<iostream>
using namespace std;
int text(int a,int b=10,int c=10)//默认参数
{
return a + b + c;
}
int main()
{
cout<<text(10, 20, 30)<<endl;
system("pause");
return 0;
}
1.3.2函数占位参数
语法:返回值类型 函数名 (数据类型){}
占位参数必须填补,占位参数中还可以有默认参数
void text(int a,int)//占位参数,目前阶段我们还用不到
{
cout << "hello word" << endl;
}
int main()
{
text(10,10);//占位参数必须填补
system("pause");
return 0;
}
1.3.3函数重载
就是让函数名相同,提高复用性。
函数重载满足条件:
- 1.在同一个作用域下
- 2.函数名相同
- 3.函数参数类型不同/个数不同/顺序不同(const int a与int a属于类型不同)
注意:函数的返回值不可以做函数重载的条件
eg:一个为void fun(int a,int b)一个为int fun(int a,int b)//错 两个都可以被调用
函数重载的注意事项:
- 1.引用作为重载的条件
- 2.函数重载碰到默认参数(会出现二义性,尽量避免)
引用作为重载的条件
void text(int &a)
{
cout << "hello word" << endl;
}
void text(const int &a)
{
cout << "hello word!" << endl;
}
int main()
{
int a = 10;
text(a);//a是一个变量,是可读可改的而第二个函数是只读的
text(10);//传入第一个那个函数不合法,而加了const的编译器会做优化
system("pause");
return 0;
}
本文详细介绍了C++中的内存分区模型,包括代码区、全局区、栈区和堆区,并通过示例代码解释了各区域的作用和管理方式。此外,讨论了引用的概念及其在函数参数传递中的应用,强调了引用的特性。最后,探讨了函数的默认参数、占位参数和重载等提高编程效率的方法,帮助理解函数在C++中的灵活使用。
390

被折叠的 条评论
为什么被折叠?



