C++核⼼编程(⿊马程序员课程讲义)
本阶段主要针对C++⾯向对象编程技术
1. 内存分区模型
C++程序在执⾏时,将内存⼤⽅向划分为4个区域:
代码区:存放函数体的⼆进制代码,由操作系统进⾏管理的
全局区:存放全局变量和静态变量以及常量
黑马程序员前端全套视频栈区:由编译器⾃动分配和释放,存放函数的参数值,局部变量等
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
内存四区的意义:不同区域存放的数据,赋予不同的⽣命周期,给予更⼤的灵活编程
1.1 程序运⾏前
在程序编译后,⽣成了exe可执⾏程序,未执⾏该程序前分为两个区域:
代码区:
存放CPU执⾏的机器指令(⼆进制)
代码区是共享的,共享的⽬的是对于频繁被执⾏的程序,只需要在内存中有⼀份代码即可(避免资源浪费)
代码区是只读的,使其只读的原因是防⽌程序意外地修改了它的指令
全局区:
全局变量和静态变量存放在此
全局区还包含了常量区,字符串常量和const修饰的全局变量(即全局常量)也存放在此(const修饰的局部变量,即局部常量,是和局部变量放在⼀块)
该区域的数据在程序结束后由操作系统释放
总结:
· C++中在程序运⾏前分为代码区和全局区
· 代码区的特点是共享和只读
· 全局区中存放全局变量,静态变量,常量
· 常量区中存放了字符串常量和const修饰的全局变量
· 局部变量和const修饰的局部变量不在全局区(在栈区)
1.2 程序运⾏后
栈区:
由编译器⾃动分配释放,存放函数的形参、局部变量等
注:不要返回局部变量的地址,栈区开辟的数据由编译器⾃动释放
堆区:
由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在C++中主要利⽤new关键字在堆区开辟内存
总结:
· 堆区数据由管理员开辟和释放
· 堆区(⾃由存储区)数据利⽤new关键字进⾏开辟内存
1.3 new操作符
C++中利⽤new操作符在堆区开辟数据
堆区开辟的数据,由程序员⼿动开辟,⼿动释放,释放利⽤操作符delete
语法:new 数据类型
new 数据类型 告诉程序需要适合存储该数据类型的内存,然后它到这样的内存,并返回其地址
1.4 delete运算符
使⽤delete时,后⾯要加上指向new分配的内存块的指针(即⽤于new的地址)
对空指针使⽤delete是安全的
注意:⼀定要配对的使⽤new和delete,否则将发⽣内存泄漏。
总结:
使⽤new和delete应遵守的规则有( C++ Primer Plus P87):
· 不要⽤delete来释放不是new分配的内存
· 不要使⽤delete释放同⼀个内存块两次
· 如果使⽤new[ ]为数组分配内存,则应使⽤delete[ ]来释放
· 如果使⽤new为⼀个实体分配内存,则应使⽤delete来释放
· 对空指针使⽤delete是安全的
2. 引⽤
2.1 引⽤的基本使⽤
作⽤:给变量起别名
语法:数据类型 & 别名 = 原名 ( 数据类型和原来的变量的类型是⼀样的)
引⽤也是地址的别名
引⽤的本质是⼀个指针常量,指针指向的值可以修改,但是指针指向的地址不能改变,占四个字节
2.2 引⽤注意事项
①引⽤必须初始化
②引⽤在初始化后,不可以改变(指针常量)
2.3 引⽤做函数参数(引⽤传递)
作⽤:函数传参时,可以利⽤引⽤的技术让形参修饰实参(C++Primer Plus P212)
优点:通过引⽤参数产⽣的效果同按地址传递是⼀样的,引⽤传递可以简化指针修改实参
2.4 引⽤做函数返回值
作⽤:引⽤是可以作为函数的返回值存在的
⽤法:如果函数的返回值是引⽤,则这个函数调⽤可以作为左值
注意:不要返回局部变量引⽤ (C++Primer Plus P312)
2.5 引⽤的本质
本质:引⽤的本质在C++内部实现是⼀个指针常量
2.6 常量引⽤
作⽤:常量引⽤主要⽤来修饰形参,防⽌误操作
在函数形参列表中,可以加const修饰形参,防⽌形参改变实参
3. 函数提⾼
3.1 函数默认参数
在C++中,函数的形参列表中的形参列表是可以有默认值的
语法:返回值类型 函数名(形参 = 默认值){ }
注意:
①如果某个位置已经有了默认参数,那么从这个位置后,从左向右都必须有默认值
②如果函数声明有默认参数,函数实现就不能有默认参数(声明和实现只有⼀个能有默认参数)
3.2 函数占位参数
C++中函数的形参列表⾥可以有占位参数,⽤来做占位,调⽤函数时必须填补该位置
语法:返回值类型 函数名 (数据类型){ }
3.3 函数重载
3.3.1函数重载概述
作⽤:函数名可以相同,提⾼复⽤性
函数重载的关键是函数的参数列表,也叫做函数特征标
函数重载的满⾜条件:
①同⼀个作⽤域下
②函数名称相同
③函数参数类型不同或者个数不同或者顺序不同
注意:函数的返回值类型不可以作为函数重载的条件
3.3.2 函数重载的注意事项
①引⽤作为重载条件
②函数重载碰到函数默认参数(产⽣歧义,要避免)
③不要滥⽤函数重载,仅当函数基本上执⾏相同的任务,但使⽤不同形式的数据时,才应该采⽤函数重载
4. 类和对象
C++⾯向对象的三⼤特性:封装、继承和多态
C++认为万事万物皆为对象,对象上有其属性和⾏为
具有相同性质的对象,可以抽象为类,⼈属于⼈类,车属于车类
类是⼀种将抽象转换为⽤户定义类型的C++⼯具,它将数据表⽰和操纵数据的⽅法组合成⼀个简洁的包。
4.1 封装
4.1.1 封装的意义
封装是C++⾯向对象三⼤特性之⼀
封装的意义:
①将属性和⾏为作为⼀个整体,表现⽣活中的事物
②将属性和⾏为加以权限控制
封装意义①:
在设计类的时候,属性(变量)和⾏为(函数)写在⼀起,表现事物(变量⼀般放在私有,函数放在公有)语法:class 类名{ 访问权限: 属性 / ⾏为 };
封装意义②:
类在设计时,可以把属性和⾏为放在不同的权限下,加以限制
访问权限有三种:
1.public 公共权限
2.protected 保护权限
3.private 私有权限
4.1.2 struct和class的区别
在C++中struct和class唯⼀的区别就在于默认的访问权限不同
区别:
①struct默认权限为公共
②class默认权限为私有
4.1.3 成员属性设置为私有
优点1:将所有成员属性设置为私有,可以⾃⼰控制读写权限
优点2:对于写权限,我们可以检测数据的有效性
4.2 对象的初始化和清理
C++中的⾯向对象来源于⽣活,每个对象也都会有初始化设置以及对象销毁前的清理数据的设置。
4.2.1 构造函数和析构函数
对象的初始化和清理也是两个⾮常重要的安全问题,⼀个对象或者变量没有初始状态,对其使⽤后果是未知;同样的使⽤完⼀个对象或变量,没有及时清理,也会造成⼀定的安全问题。
C++利⽤了构造函数(做初始化)和析构函数(清理)解决上述问题,这两个函数将会被编译器⾃动调⽤,完成对象初始化和清理⼯作。如果我们不提供构造和析构,编译器会提供,编译器提供的构造函数和析构函数是空实现。
**构造函数:**主要作⽤在创建对象时为对象的成员属性赋值,构造函数由编译器⾃动调⽤,⽆需⼿动调⽤。
语法:类名(){}
1.构造函数,没有返回值也不写void
2.函数名称与类名相同
3.构造函数可以有参数,因此可以发⽣重载
4.程序在调⽤对象的时候会⾃动调⽤构造,⽆需⼿动调⽤,⽽且只会调⽤⼀次
**析构函数:**主要作⽤在对象销毁前系统⾃动调⽤,执⾏⼀些清理⼯作。
语法:~类名(){}
1.析构函数,没有返回值也不写void
2.函数名称与类名相同,在名称前⾯加~
3.析构函数不可以有参数,因此不可以发⽣重载
4.程序在对象销毁前会⾃动调⽤析构,⽆需⼿动调⽤,⽽且只会调⽤⼀次
4.2.2 构造函数的分类及调⽤
两种分类⽅式:
按参数分为:有参构造和⽆参构造(默认构造函数)
按类型分为:普通构造和拷贝构造
三种调⽤⽅式:
括号法(常⽤)、显式法、隐式转换法
注意:
①调⽤⽆参构造函数不能加括号,如果加了括号,编译器会认为这是⼀个函数声明
②不要利⽤拷贝构造函数初始化匿名对象,编译器认为是对象声明
匿名对象的特点:当前⾏执⾏结束后,系统会⽴即回收掉匿名对象
4.2.3 拷贝构造函数调⽤时机
通常有三种情况:
· 使⽤⼀个已经创建完毕的对象来初始化⼀个新对象;
· 值传递的⽅式给函数参数传值;
· 以值⽅式返回局部对象
4.2.4 构造函数调⽤规则
默认情况下,C++编译器⾄少给⼀个类添加3个函数
①默认构造函数(⽆参,函数体为空)
②默认析构函数(⽆参,函数体为空)
③默认拷贝构造函数,对属性进⾏值拷贝
构造函数调⽤规则如下:
· 如果⽤户定义有参构造函数,C++不再提供默认⽆参构造,但是会提供默认拷贝构造;
·
如果⽤户定义拷贝构造函数,C++不会再提供其他构造函数
4.2.5 深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝操作(
深拷贝:在堆区重新申请空间(new),进⾏拷贝操作
总结:如果属性有在堆区开辟的,必须要⾃⼰提供拷贝构造函数,防⽌浅拷贝带来的堆区内存重复释放问题
4.2.6 初始化列表
作⽤:C++提供了初始化列表语法,⽤来初始化属性
语法:构造函数():属性1(值1),属性2(值2)···{}
4.2.7 类对象作为类成员
C++类中的成员可以是另⼀个类的对象,称该成员为对象成员
B类中有对象A作为成员,A为对象成员
当创建B对象时,A与B的构造和析构的顺序是谁先谁后?
构造顺序:先调⽤对象成员的构造,再调⽤本类构造
析构顺序与构造顺序相反
4.2.8 静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:
· 静态成员变量:所有对象共享同⼀份数据;在编译阶段分配内存;类内声明,类外初始化(加上作⽤域,类名 ::)
注:
①静态成员变量不属于某个对象上,所有对象都共享同⼀份数据,因此可以有两种访问⽅式:通过对象进⾏访问、通过类名进⾏访问
②静态成员变量也是有访问权限的
· 静态成员函数:所有对象共享同⼀个函数;静态成员函数只能访问静态成员变量
注:
①同样,静态成员函数也是两种访问⽅式:通过对象访问、通过类名访问
②静态成员函数也是有访问权限的
4.3 C++对象模型和this指针
4.3.1 成员变量和成员函数分开存储
在C++中,类内的成员变量和成员函数分开存储
总结:只有⾮静态成员变量才属于类的对象上
4.3.2this 指针概念
每⼀个⾮静态成员函数只会诞⽣⼀份函数实例,也就是说,多个同类型的对象会共⽤⼀块代码,问题是:这⼀块代码是如何区分哪个对象调⽤⾃⼰?
C++通过提供特殊的对象指针——this指针——解决上述问题。
this指针指向被调⽤的成员函数所属的对象
this指针是隐含每⼀个⾮静态成员函数内的⼀种指针
this指针不需要定义,直接使⽤即可
⽤途①:当形参和成员变量同名时,可⽤this指针来区分

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。