C++学习笔记(二)

1、内区分区模型

在这里插入图片描述
在这里插入图片描述

1.1 全局区

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

全局变量和静态变量离得很近

在这里插入图片描述

1.2 栈区

由编译器自动分配释放,存放函数的参数值,局部变量等
注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

在这里插入图片描述
在这里插入图片描述

1.3 堆区

由程序员分配释放,若程序员不释放,程序结束时由操作系统回收,在C++中主要利用new在堆区开辟内存

在这里插入图片描述
在这里插入图片描述

1.4 new运算符

C++中利用new操作符在堆区开辟数据;
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符delete;
语法:new 数据类型;
利用new创建的数据,会返回该数据对应的类型的指针

在这里插入图片描述
在这里插入图片描述

2 引用

2.1 引用的基本使用

作用:给变量起别名
语法:数据类型 &别名=原名

在这里插入图片描述

2.2 引用注意事项
  • 引用必须初始化
  • 引用在初始化后,不可以改变

 在这里插入图片描述

2.3 引用做函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针修改实参

在这里插入图片描述
在这里插入图片描述

通过引用参数产生的效果同按地址传递是一样的,引用的语法更清楚简单

2.4 引用做函数返回值

作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量引用
用法:函数调用作为左值

在这里插入图片描述
在这里插入图片描述

2.5 引用的本质

引用的本质是一个指针常量,一旦初始化后,指向不可改变

在这里插入图片描述
在这里插入图片描述

C++推荐使用引用技术,因为语法方便,引用本质是指针常量,但是所有的指针操作编译器都帮我们做了

2.6 常量引用

作用:常量引用主要用来修饰形参,防止误操作;
在函数形参列表中,可以加const修饰形参,防止形参改变实参

在这里插入图片描述

3、函数提高

3.1 函数默认参数

在C++中,函数的形参列表中的形参是可以有默认值的
语法:返回值类型 函数名(参数=默认值){ }

在这里插入图片描述

3.2 函数的占位参数

C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置

3.3 函数重载

作用:函数名可以相同,提高复用性

函数重载满足条件:

  • 同一个作用域下
  • 函数名称相同
  • 函数参数类型不同,或者个数不同或者顺序不同
    在这里插入图片描述
    在这里插入图片描述

函数重载注意事项:
1.引用作为重载条件
2.函数重载碰到函数默认参数

在这里插入图片描述
在这里插入图片描述

4、类和对象

C++面向对象三大特性:封装、继承和多态

4.1 封装

封装的意义

  • 将属性和行为作为一个整体,表现生活中的事物
  • 将属性和行为加以权限控制

语法:

class 类名{访问权限:属性 /行为}

类在设计时,可以把属性和行为放在不同的权限下,加以控制访问权限有三种:

  1. public 公共权限
  2. protected 保护权限
  3. private 私有权限

在这里插入图片描述

4.1.1 struct和class区别

在C++中struct和class唯一的区别就在于默认的访问权限不同:

  • struct默认权限为公共
  • class默认权限 为私有
    在这里插入图片描述
4.1.2 成员属性设置为私有
  • 优点1:将所有成员属性设置为私有,可以自己控制读写权限
  • 优点2:对于写权限,我们可以检测数据的有效性
4.2 对象的初始化和清理

构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作

如果我们不提供构造和析构,编译器会提供,编译器提供的构造函数和析构函数是空实现

4.3 构造函数的分类及调用

两种分类方式:

按参数分为:有参构造和无参构造
按类型分为:普通构造和拷贝构造

三种调用方式:

  1. 括号法
  2. 显示法
  3. 隐式转换法

在这里插入图片描述
在这里插入图片描述
括号法:
在这里插入图片描述
显示法:
在这里插入图片描述
匿名对象
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
隐式转换法
在这里插入图片描述

4.3.1 拷贝构造函数调用时机

C++中拷贝构造函数调用时机通常有三种情况:

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象

1.使用一个已经创建完毕的对象来初始化一个新对象
在这里插入图片描述

2.值传递的方式给函数参数传值
在这里插入图片描述
3.值的方式返回局部对象
在这里插入图片描述

4.3.2 构造函数调用规则

默认情况下,C++编译器至少给一个类添加3个函数

  • 默认构造函数(无参,函数体为空)
  • 默认析构函数(无参,函数体为空)
  • 默认拷贝构造函数,对属性进行值拷贝

构造函数调用规则如下:

  • 如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造
  • 如果用户定义拷贝构造函数,C++不会再提供其他构造函数
4.3.3 深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作

在这里插入图片描述

浅拷贝带来的问题就是堆区的内存重复释放

在这里插入图片描述

深拷贝就是自己实现拷贝构造函数,在堆区重新创建内存空间 ,解决浅拷贝带来的问题,析构函数可以释放堆区内存;
如果不利于深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题

在这里插入图片描述

总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

4.3.4 初始化列表

作用:C++提供了初始化列表语法,用来初始化属性
语法:构造函数():属性1(值1),属性2(值2)……{}

在这里插入图片描述

4.3.5 类对象作为类成员

C++类中的成员可以是另一个类的对象,称该成员为对象成员

构造顺序是:先调用对象成员的构造,再调用本类构造;
析构顺序与构造相反

4.3.6 静态成员

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员变量

  • 所有对象共享同一份数据
  • 在编译阶段分配内存
  • 类内声明,类外初始化
    在这里插入图片描述

静态成员函数

  • 所有对象共享同一个函数
  • 静态成员函数只能访问静态成员变量
    在这里插入图片描述
4.4 C++对象模型和this指针
4.4.1 C++对象模型

在C++中,类内的成员变量和成员函数分开存储;
只有非静态成员变量才属于类的对象上

空对象占用内存为1

在这里插入图片描述

4.4.2 this指针

每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
问题:这一块代码是如何区分哪个对象调用自己呢

C++通过提供特殊的对象指针,this指针,解决上述问题
this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可

this指针的用途:

  1. 当形参和成员变量同名时,可用this指针来区分 ;this可以直接用,不需要定义
    在这里插入图片描述

  2. 在类的非静态成员函数中返回对象本身,可使用return *this(可实现链式编程)

    在这里插入图片描述
    如果以值的形式返回 ,会创建新对象,但是以引用形式不会创建新对象
    在这里插入图片描述

在这里插入图片描述

4.4.3 空指针访问成员函数

空指针可以调用成员函数,但是要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性


在这里插入图片描述

在这里插入图片描述

4.3.4 const修饰成员函数

常函数:

  • 成员函数加const后称为常函数
  • 常函数不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依旧可以修改

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数
    在这里插入图片描述
4.4 友元

在程序里,有些私有属性,也想让类外特殊的一些函数或者类进行访问,就需要用到友元技术

友元的目的就是让一个函数或者类访问另一个类中私有成员

友元关键字为friend

友元的三种实现:

  • 全局函数做友元

    在这里插入图片描述

  • 类做友元
    在这里插入图片描述
    在这里插入图片描述

  • 成员函数做友元
    在这里插入图片描述

    在这里插入图片描述

4.5 运算符重载

对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

4.5.1 加号运算符重载

作用:实现两个自定义数据类型相加的运算

在这里插入图片描述

1.成员函数重载+号

在这里插入图片描述
在这里插入图片描述

2.通过全局函数重载+号

4.5.2 左移运算符重载

在这里插入图片描述
在这里插入图片描述

4.5.3 递增运算符重载

通过重载递增运算符,实现自己的整型数据
前置递增返回引用,后置递增返回值

在这里插入图片描述
在这里插入图片描述

4.5.4 赋值运算符重载

C++编译器至少给一个类添加4个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝
  4. 赋值运算符operator=对属性进行值拷贝

如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

4.5.5 关系运算符重载

作用:重载关系运算符,可以让两个自定义类型对象进行对比操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.5.6 关系运算符重载
  • 函数调用运算符()也可以重载
  • 由于重载后使用的方式非常像函数的调用,因此称为仿函数
  • 仿函数没有固定写法,非常灵活
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

4.6 继承

继承的好处:减少重复代码

语法:class 子类:继承方式 父类

子类也称为派生类,父类也称为基类
派生类中的成员包括两大部分,一类是从基类继承过来的,一类是自己增加的成员,从基类继承过来的表现其共性,而新增的成员体现了其个性

4.6.1 继承方式
  • 公共继承
  • 保护继承
  • 私有继承

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.6.2 继承中的对象模型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.6.3 继承中的构造和析构顺序

先构造父类,再构造子类,析构的顺序与构造的顺序相反

4.6.4 继承中的同名成员处理

在这里插入图片描述
在这里插入图片描述在这里插入图片描述 在这里插入图片描述
在这里插入图片描述

4.6.5 继承同名静态成员处理方式

静态成员和非静态成员出现同名,处理方式一致

  • 访问子类同名成员,直接访问即可
  • 访问父类同名成员,需要加作用域

1.静态成员变量
在这里插入图片描述
访问静态成员属性的两种方式:

  • 通过对象访问
  • 通过类名访问

在这里插入图片描述

2.静态成员函数

在这里插入图片描述

4.6.6 多继承语法

C++允许一个类继承多个类(不建议)

语法:class 子类:继承方式 父类1,继承方式 父类2

多继承可能会引发父类中有同名成员出现,需要加作用域区分

4.6.7 菱形继承

概念:

两个派生类继承同一个基类,又有某个类同时继承着两个派生类,这种继承被称为菱形继承
在这里插入图片描述

在这里插入图片描述

菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费
利用虚继承可以解决菱形继承问题

4.7 多态

多态分为两类

  • 静态多态:函数重载和运算符重载属于静态多态,复用函数名
  • 动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定-编译阶段确定函数地址
  • 动态多态的函数地址晚绑定-运行阶段确定函数地址

动态多态满足条件:
1.有继承关系
2.子类重写父类的虚函数

动态多态的使用:
父类的指针或者引用执行子类对象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

4.7.1 多态的原理剖析

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

当父类的指针或者引用指向子类对象时候,发生多态

在这里插入图片描述

4.7.2 多态的优点
  • 代码组织结构清晰
  • 可读性强
  • 利于前期和后期的扩展以及维护

C++开发提倡利用多态设计程序架构,因为多态优点很多

1.普通实现

在这里插入图片描述
2.多态实现

在这里插入图片描述
在这里插入图片描述

4.7.3 纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数

纯虚函数语法:virtual 返回值类型 函数名(参数列表)=0

当类中有了纯虚函数,这个类也称为抽象类

抽象类特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
    在这里插入图片描述
4.7.4 虚析构和纯虚析构

问题:多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构函数
解决方式 :将父类中的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构共性:
1.可以解决父类指针释放子类对象
2.都需要有具体的函数实现

虚析构和纯虚析构区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
在这里插入图片描述

父类指针在析构时候不会调用子类中析构函数,导致子类如果有堆区属性,出现内存泄漏
在这里插入图片描述
在这里插入图片描述
将父类析构函数改为虚析构
在这里插入图片描述
纯虚函数只需要声明,纯虚析构需要声明也需要实现
有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
在这里插入图片描述

总结:
1.虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2.如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3.拥有纯虚析构函数的类也属于抽象类

5 文件操作

程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
C++中对文件操作需要包含头文件< fstream >

文件类型分为两种:

  1. 文本文件:文件以文本的ASCII码形式存储在计算机中
  2. 二进制文件:文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们

操作文件的三大类:
1.ofstream:写操作
2.ifstream:读操作
3.fstream:读写操作

5.1 文本文件
5.1.1 写文件

写文件步骤:
在这里插入图片描述
文件打开方式:
在这里插入图片描述

注意:文件打开方式可以配合使用,利用 | 操作符

5.1.2 读文件

读文件步骤:
在这里插入图片描述
在这里插入图片描述

5.2 二进制文件

以二进制的方式对文件进行读写操作
打开方式要指定为ios::binary

5.2.1 写文件

在这里插入图片描述
在这里插入图片描述

5.2.2 读文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值