内存
内存分区模型
代码区:存放函数体的二进制代码,由操作系统进行管理 全局区:存放全局变量、静态变量和常量 栈区:由编译器自动分配释放,存放函数的参数值、局部变量等 堆区:由程序员分配释放,若程序员不释放,程序结束时由操作系统回收 内存分区意义:不同分区存放的数据,赋予不同的生命周期,灵活编程
程序运行前
程序编译后,生成.exe
可执行程序,未执行该程序前,分为两个区域:
代码区:
- 存放CPU执行的机器指令
- 代码区是共享的,目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
- 代码区是只读的,防止程序意外的修改了它的指令
全局区:
- 存放全局变量、静态变量(
static
)和常量(字符串常量、const
修饰的全局变量) - 该区域的数据在程序结束后由操作系统释放
程序运行后
栈区: 由编译器自动分配释放,存放函数的参数值、局部变量等 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
int* test()//形参也会存放在栈区
{
int a = 10;//局部变量,存放在栈区,栈区的数据在函数执行完后被自动释放
return &a;//返回局部变量地址
}
堆区:
由程序员分配释放,若程序员不释放,程序结束时,由操作系统回收
在C++中主要利用new
在堆区开辟内存
int* test()
{
//利用new关键字,可以将数据开辟到堆区
//指针也是局部变量,放在栈上,指针保存的数据是放在堆区
int* p = new int(10);
return p;
}
new操作符
new
在堆区开辟数据,释放利用delete
利用new
创建的数据,会返回该数据对应的类型的指针
void test()
{
int* p = new int(10);
cout << *p << endl;
delete p;
cout << *p << endl;//使用未初始化的内存p
}
也可以加中括号[]
开辟或释放数组
void test()
{
int* p = new int[10];
for (int i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (int i = 0; i < 10; i++)
{
cout << *(p + i) << endl;
}
//释放数组时,要加中括号才可以
delete[] p;
}
作用:给变量起别名
语法:数据类型 &别名 = 原名
int main()
{
int a = 10;
//引用必须初始化,一旦初始化,就不可以更改
int& b = a;
b = 100;
cout << "a=" << a << endl;//100
cout << "b=" << b << endl;//100
return 0;
}
引用
引用作函数参数
作用:函数传参时,可以利用引用的技术让形参修饰实参 优点:可以简化指针 修改实参
//引用传递
void test2(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10, b = 20;
test2(a, b);//引用传递
cout << "a=" << a << endl;//20
cout << "b=" << b << endl;//10
return 0;
}
通过引用参数产生的效果和地址传递是一样的,引用的语法更清楚简单
引用作函数返回值
- 不要返回局部变量引用
- 函数的调用可以作为左值
int& test()
{
//静态变量存放在全局区,程序结束时由系统释放
static int a = 10;
return a;
}
int main()
{
int& a = test();
cout << a << endl;//10
cout << test() << endl;//10
//函数调用可以作为左值
test() = 100;
cout << a << endl;//100
cout << test() << endl;//100
return 0;
}
引用的本质
本质:一个指针常量 C++推荐用引用技术,因为语法方便,引用本质是指针常量,但是所有的指针操作,编译器都帮我们做了
//发现是引用,转化为int* const ref =&a;
void test(int& ref)
{
ref = 100;
}
int main()
{
int a = 10;
//自动转换为int* const ref =&a;指针常量是指针指向不可改,也说明为什么引用不可改
int& ref = a;
//内部发现是引用,自动转换为:*ref = 20;
ref = 20;
cout << "a=" << a << endl;//20
cout << "ref=" << ref << endl;//20
test(a);
cout << "a=" << a << endl;//100
return 0;
}
常量引用
用来修饰形参,防止误操作
引用要引用合法的内存空间:const int& a = 10;
void test(const int& a)
{
···
}
函数
函数默认参数
注意事项:
- 如果某个位置已经有了默认参数,则从这个位置往后,从左到右,都必须有默认值
- 函数声明和函数实现,只能有一个有默认参数
//如果某个位置已经有了默认参数,则从这个位置往后,从左到右,都必须有默认值
void test0(int a, int b = 10, int c = 10)
{
cout << a + b + c << endl;
}
//函数声明和函数实现,只能有一个有默认参数
int test1(int a = 10, int b = 10);
int main()
{
test0(5, 1);//16
cout << test1() << endl;//20
return 0;
}
int test1(int a, int b)
{
return a + b;
}
函数占位参数
C++函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法:返回值类型 函数名 (数据类型) {}
//占位参数也可以有默认参数
void test(int a, int = 10)
{
}
函数重载
作用:函数名可以相同,提高复用性 函数重载满足条件:
- 同一作用域下
- 函数名称相同
- 函数参数类型不同,或者个数不同,或者顺序不同
注意事项
- 引用作为重载的条件
- 当函数重载碰到默认参数,会出现二义性
//引用作为重载的条件
void test0(int& a)//int &a = 10;不合法
{
cout << "test0" << endl;
}
void test0(const int& a)//const int &a = 10;合法
{
cout << "test1" << endl;
}
int main()
{
int a = 10;
test0(a);//test0
test0(10);//test1
return 0;
}
C++面向对象的三大特性:封装、继承、多态 C++认为万事万物皆为对象,对象上有其属性和行为 具有相同性质的对象,我们可以抽象成为类,人属于人类,车属于车类
封装
封装的意义
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
class circle
{
//访问权限
public://公共权限
//属性
int r;//半径
//行为
double c()//获取周长
{
return 2 * 3.14 * r;
}
};
int main()
{
//实例化:通过一个类,创建一个对象
circle a;
//给对象属性赋值
a.r = 10;
cout << a.c() << endl;//62.8
return 0;
}
访问权限
public
公共权限:成员 类内可以访问,类外可以访问protected
保护权限:成员 类内可以访问,类外不可访问,儿子可以访问父亲中的保护内容private
私有权限:成员 类内可以访问,类外不可访问,儿子不可以访问父亲中的私有内容
struct
与class
区别
在C++中struct
与class
唯一的区别在于默认的访问权限不同
struct
默认权限为公共class
默认权限为私有
struct test1
{
int a;
};
class test2
{
int a;
};
int main()
{
test1 a1;
a1.a = 10;//可以访问
test2 a2;
a2.a = 10;//不可访问
return 0;
}
成员属性私有化
优点
- 将所有成员属性设置为私有,可以自己控制读写权限
- 对于写权限,可以检测数据的有效性
class person
{
private:
string name;
public:
void setname(string name1)
{
name = name1;
}
string getname()
{
return name;
}
};
int main()
{
person a1;
a1.setname("张三");
cout << a1.getname() << endl;
return 0;
}