c++程序在执行时,将内存大方向划分为4个区域
代码区:存放函数体的二进制代码,由操作系统进行管理的
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
不同区域存放的数据,赋予不同生命周期,给我们更大的灵活编程。
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域:
- 存放CPU执行的机器指令:二进制01010。
- 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。
- 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令。
- 全局变量和静态变量存放在此。
- 全局区还包含了常量区,字符串常量和其他常量也存放在此。
- 该区域的数据在程序结束后由操作系统释放。
全局区存放的数据:全局变量、静态变量、常量。
// 全局区:存放:全局变量、静态变量、常量。 // 创建普通局部变量 // 静态变量: 在普通变量前面加上static // 常量:分为字符串常量和const修饰的变量。 // 字符串常量:双引号引起来的字符串,都可以被称为字符串常量。"Hello world."。 // const修饰变量:还可以分为:const修饰的全局常量,const修饰的局部变量(局部常量)。局部变量:在函数体内声明的变量。包括main函数内。
全局变量:在函数体外声明的变量。
由自动分配和释放,存放函数的参数值,局部变量等。
int a = 10; // 局部变量 存放在栈区,栈区的数据在函数执行完后自动释放。注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。
由程序员分配释放,若程序员不释放,程序结束时由操作系统回收。
在C++中主要利用new关键字在堆区开辟内存。
// 利用 new关键字 将数据开辟到 堆区。 // 指针本质也是局部变量,也是放在栈区,只是指针保存的实际数据在堆区。指针是一种类型。4个字节,保存在栈中,栈的数据内容为指向的内存地址。
用new关键字可以在内存堆中开辟空间存储数据。
新建一个指向A类型的数据在堆中的地址这样一个变量。
可以由程序员释放内存空间:delete
// 在堆区创建一个整型数据。 // new 返回的是:该数据类型的指针。 // 在堆中的数据,只要程序员不主动释放,那么就一直存在。 // 堆区的数据,由程序员管理开辟,程序员管理释放。 // 如果想释放堆区的数据,利用关键字delete // 在堆区开辟一个数组: // 释放数组的时候,要加[]才可以。 //别名数据变 原也变
作用:函数传参时,可以利用引用的技术让形参修饰实参,
优点:可以简化指针修改实参
总结:引用传递和指针传递所得到的结果是相同的,引用传递是因为别名的原因。
作用:引用时可以作为函数的返回值存在的,
注意:不要返回局部变量引用
用法:函数调用作为左值
本质:引用的本质在c++内部实现是一个指针常量
//本质:引用的本质在C++内部实现是一个指针常量 //指针常量是指针指向的地址不可修改 而地址上的值是可以修改的。 //C++推荐引用技术 因为语法上很简单 引用本质是指针变量 但是所有的指针操作编译器帮我们做在c++中,函数的形参列表中的形参是可以有默认值的。
语法:返回值类型 函数名(参数=默认值){}
//1. 如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值 //2. 如果函数声明有默认值,函数实现的时候就不能有默认参数C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法: 返回值类型 函数名 (数据类型){}
在现阶段函数的占位参数存在意义不大,但是后面的课程中会用到该技术
//函数占位参数 ,占位参数也可以有默认参数作用: 函数名可以相同,提高复用性
注意: 函数的返回值不可以作为函数重载的条件
//函数重载需要函数都在同一个作用域下 //函数返回值不可以作为函数重载条件C++面向对象的三大特性为:封装、继承、多态。
C++认为万事万物都皆为对象,对象上有其属性和行为
人可以作为对象,属性有姓名、年龄、身高、体重...行为有走、跑、跳、吃饭、唱歌...
具有相同性质的对象,我们可以抽象称为类,人属于人类,车属于车类
封装是C++面向对象三大特性之一
语法:class 类名{ 访问权限: 属性 / 行为 };
示例1:设计一个圆类,求圆的周长
//设计一个圆类,求圆的周长 //圆求周长公式:2*PI*半径 //class代表设计一个类,类后面紧跟着的就是类的名称 //通过圆类 创建具体的圆(对象) //实例化(通过一个类 创建一个对象的过程) //给圆对象 的属性进行赋值设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生好的姓名和学号
//类中的属性和行为 我们统一称为 成员 //属性 成员属性 成员变量 //行为 成员函数 成员方法优点1: 将所有成员属性设置为私有,可以自己控制读写权限
优点2:对于写权限,我们可以检测数据的有效性
设计立方体类(Cube)
求出立方体的面积和体积
分别用全局函数和成员函数判断两个立方体是否相等
//3.设计行为 获取立方体的面积和体积 //4.分别利用全局函数和成员函数 判断两个立方体是否相等 //利用成员函数判断两个立方体是否相等 //利用全局函数判断 两个立方体是否相等 //创建一个立方体对象 //利用全局函数判断的设计一个圆形类(Circle),和一个点类(Point),计算点和圆的关系
//在类中可以让另一个类 作为本类的一个成员 //计算两点距离的平方对象和初始化和清理也是两个非常重要的安全问题
一个对象或者变量没有初始状态,对其使用后果是未知
同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题
C++利用了构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。
对象的初始化和清理工作是编译器前置我们做的事情,因此如果我们不提供构造和析构,编译器会提供
编译器提供的构造函数和析构函数是空实现
构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作
构造函数语法:类名(){}
C++中拷贝构造函数调用时机通常有三种情况
使用一个已经创建完毕的对象来初始化一个新对象
值传递的方式给函数参数传值
// 1.使用一个已经创建完毕的对象来初始化一个新对象 // 2.值传递的方式给函数参数传值 // 3.以值方式返回局部对象默认情况下,c++编译器至少给一个类添加3个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下:
如果用户定义有参构造函数,c++不在提供无参构造,但是会提供默认拷贝构造
如果用户定义拷贝构造函数,c++不会再提供其他构造函数
//如果写了有参构造函数,编译器就不会再提供无参构造函数,但依然会提供拷贝构造函数 //如果写了拷贝构造函数,编译器既不会提供无参构造函数也不会提供有参构造函数浅拷贝:简单的赋值拷贝操作。
深拷贝:在堆区中重新申请空间,进行拷贝操作。
//自己实现拷贝构造函数 解决浅拷贝带来的问题 //析构代码,将堆区开辟数据做释放操作作用:C++提供了初始化列表语法,用来初始化属性
语法:构造函数( ):属性1(值1),属性2(值2)… { }
//初始化列表:初始化属性C++类中的成员可以是另一个类的对象,我们称该成员为对象成员
静态成员就是在成员函数前加上关键字static,称为静态成员
1、所有对象共享同一份数据;
3、类内声明,类外初始化。
静态成员函数:
1、所有对象共享同一个函数;
2、静态成员函数只能访问静态成员变量。
报错,无法解析p.m_A,因为类外无法访问,要先在类外初始化才行,而且必须是在全局范围初始化。
在全局范围类外初始化要这样写:数据类型 类名::属性=初始化值
所有对象共享同一份数据
p和p2共享同一个m_A,所以都是100
扩展一个知识,可以用对象进行访问或者用类名进行访问
这里主函数里用两种方法访问m_A的值,都是正确的。因为这个m_A是所有对象公用的,所以可以通过类名访问,不需要写出是哪个对象的m_A
把m_A的访问权限改为private,在主函数里就无法访问m_A了
1、在类中m_B无法赋值,因为静态成员函数只能访问静态成员变量;
2、主函数里访问func2()函数报错,因为func2()函数时private的访问权限,类外无法访问。
只有非变量存储在类的对象中
1.空对象有一个字节,用来区分对象
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
那么问题是:这块代码是如何区分那个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
当形参和成员变量同名时,可用this指针来区分
在类的非静态成员函数中返回对象本身,可使用return *this
//1、当形参和成员变量同名时,可用this指针来区分,解决名称冲突
C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性
//空指针访问成员函数 p->ShowPerson(); //不能访问成员变量,成员函数中用this指针判断空指针,就可以了。生活中你的家有客厅(Public),有你的卧室(Private)
客厅所有来的客人都可以进去,但是你的卧室是私有的,
在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
友元的目的就是让一个函数或者类 访问另一个类中私有成员
运算符重载概念:对已有的运算符重新定义,赋予另一种功能,以适应不同的数据类型
作用:实现两个自定义数据类型相加的运算。
//成员函数实现 + 号运算符重载 //全局函数实现 + 号运算符重载 //运算符重载 可以发生函数重载