C++学习记录——사 类和对象(1)

news2024/11/15 23:34:10

文章目录

  • 1、面向对象和面向过程的初步理解
  • 2、类的引入
  • 3、类的定义
  • 4、类的访问限定符及封装
    • 1、访问限定符
    • 2、封装
  • 5.类的实例化
  • 6、类对象模型
  • 7、this
    • 1、this指针
    • 2、空指针问题
    • 3、C语言和C++简单对比


1、面向对象和面向过程的初步理解

C语言是一个面向过程的语言,C++是一个面向对象的语言,但不是纯粹的面向对象。C++兼容C,所以过程或者对象都可以写。用洗衣服来举例子,面向过程的思路就是想象我要做的所有事,往洗衣机倒入洗衣液,倒水,把衣服放进去,选择哪个按钮,等待洗完,再甩干等等。而面向对象的思路就是总共有四个对象,人,洗衣液,洗衣机,衣服,人只要想好和每个对象是如何交互地即可,不去想应当选择哪个按钮等等。面向对象注重的是对象之间的交互。

2、类的引入

C语言的结构体里面只能放入数据,而C++的结构体不仅可以放入数据,还可以放入函数,一个叫成员变量,一个叫成员函数。C++把结构体升级成了类。

C语言中栈的实现是一个结构体,然后外面再跟很多函数的声明,另一个文件放定义。C++会是这样实现。

struct Stack
{
	//数据和方法在一起
	//成员函数
	void Init(int n = 4)
	{
		a = (int*)malloc(sizeof(int) * capacity);
		if (nullptr == a)
		{
			perror("malloc申请空间失败");
			return;
		}
		capacity = n;
		size = 0;
	}

	void Push(int x)
	{
		a[size] = x;
	}

	//成员变量
	int* a;
	int size;
	int capacity;
};

在这个结构体里,同时拥有函数和变量,我们也不需要写StackInit作为函数名,因为这是在Stack这个类里的,系统知道这是栈的初始化函数。如果要创建一个栈,那么直接Stack st即可,因为C++把这个Stack就当作类型。类是一个整体,无论放到哪里,系统都会去全局搜索它。

使用的时候

int main()
{
	Stack st;//st就是一个对象
	st.Init();
	st.Push(1);
	st.Push(2);
	st.Push(3);
	return 0;
}

由于上面的Init是由缺省参数的,所以这里可以不用传参。

3、类的定义

class className
{
	// 类体:由成员函数和成员变量组成
};  // 注意后面要有分号

实际上C++中定义类是用class这个关键字的,ClassName就是类名,类体中的内容称为类的成员,类中的变量称为类的属性或成员变量,类中的函数称为类的方法或者成员函数。

上面是成员函数定义到类里面,那么如C语言一样,C++是否也可以声明和定义分离?

Stack.h

#pragma once
#include <stdlib.h>
#include <iostream>
using namespace std;

struct Stack
{
	void Init(int n = 4);
	void Push(int x);

	int* a;
	int size;
	int capacity;
};

Stack.cpp

#include "Stack.h"

void Stack::Init(int n)
{
	a = (int*)malloc(sizeof(int) * capacity);
	if (nullptr == a)
	{
		perror("malloc申请空间失败");
		return;
	}
	capacity = n;
	size = 0;
}

void Stack::Push(int x)
{
	a[size] = x;
}

这里面加上::是让编译器知道,这个函数栈类的成员函数,那么编译器就会去类里面找这个函数。::也是标明了类的作用域是在哪里。

test.cpp

#include "Stack.h"

int main()
{
	Stack st;
	st.Init();
	st.Push(1);
	st.Push(2);
	st.Push(3);
	return 0;
}

4、类的访问限定符及封装

1、访问限定符

Stack.h文件里,可不可以把struct换成class?换了后就是这样:

在这里插入图片描述

C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。

访问限定符有private(私有),protected(保护), public(公有)三个,现阶段可以把保护和私有看成一个。看下面的规则。

【访问限定符说明】

  1. public修饰的成员在类外可以直接被访问
  2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  4. 如果后面没有访问限定符,作用域就到 } 即类结束。
  5. class的默认访问权限为private,struct为public(因为struct要兼容C)

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

不管是用struct还是class,我们都可以定义类的内容为公还是私。

在这里插入图片描述
这样程序就跑得开了。

struct因为适配C语言,所以它即可以把后面的Stack作为类型,也可以struct Stack作为类型。

实际写的时候,类里面函数参数和变量名字冲突时,会改一下变量名字,比如加上_,如果不改的话,编译无法通过, 这时候编译器遵循局部优先的规定,而函数形参更优先,所以在函数里,相当于形参给形参赋值,就会出问题。

2、封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。

封装本质是为了一种更好的管理。

封装后面再提。

5.类的实例化

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;//声明
	int _month;
	int _day;
};

类中的成员变量,实际上都是在声明,即使里面有成型的函数,也只是在声明,如果在main函数中创建了一个这个classname类型的变量,那么此时类就实例化了,也就是开空间了,那么这些定义的变量和函数才在系统空间中存在。

形象化的例子就是建筑图纸,图纸上把要做的模样都已经写了出来,但是这个图纸不是实际的房子,实例化就是按照图纸建造房子。类像是一个计划,而实例化则是实际的行动。

	Date._year = 1;
	Date::_year = 0;

所以像这样是不行的,我们无法把数据存入数据里。

int main()
{
	Date d1;
	Date d2;

	d1.Init(2023, 2, 2);
	return 0;
}

这样即可。

6、类对象模型

上面的类中,成员函数是定义的,不是声明,那么实例化也是把这个函数实例化出来了吗?

int main()
{
	Date d1;
	Date d2;

	d1.Init(2023, 2, 3);
	cout << sizeof(d1) << endl;
	return 0;
}

结果是12.所以可以看出算的只是三个int类型的变量,成员函数并没有计算。那为什成员函数不在对象里,而成员变量在对象里?

int main()
{
	Date d1;
	Date d2;

	d1.Init(2023, 2, 3);
	d1._year++;

	d2.Init(2022, 2, 3);
	d2._year++;

	cout << sizeof(d1) << endl;
	return 0;
}

把成员变量变成公有的。d1和d2的_year是不一样的,但成员函数是一样的,都是一样的代码实现。成员函数是不在对象里的,如果在的话空间浪费就多了,这就像宿舍里的浴室,每一层楼都有一个公共的,这也就是成员函数,而成员变量就是住的学生。当然每个屋独立卫生间这得加钱。

成员变量独立存储,成员函数放到代码段(共享公共空间)

类的计算也就是结构体的计算规则——内存对齐

  1. 第一个成员在与结构体偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的对齐数为8
  3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
    体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

7、this

1、this指针

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

public:
	int _year;//声明
	int _month;
	int _day;
};

在这段代码中,成员函数里day赋值给了_day,可是这个_day能接收它吗?在类里它只是一个声明,那么外面的实例化中,有个d1,调用了函数,给d1的成员变量的实例化赋值。我们似乎可以想到这个答案,但是这个共享函数,怎么知道是要给d1的成员变量赋值?为什么不会给d2?

C++是这样解决的,在处理这些代码的时候,会用一个关键字this,会在函数括号里加上对应类型的this指针,然后在函数内容里会变成this -> _day, 而在main函数里,用d1调用Init时,就会在括号里加上一个d1的地址,所以才保证了唯一的调用。

	void Init(Date* this, int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	d1.Init(&d1, 2023, 2, 3);
	d1._year++;

	d2.Init(&d2, 2022, 2, 3);
	d2._year++;

但操作者不可以自己加上this,会出错。不过我们在函数里面可以加上this。

	void Init(int year, int month, int day)
	{
		cout << this << endl;
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

在这里插入图片描述

这就是两个this指针的地址。

this指针存在栈上。this是一个形参,隐含的形参,因为这是编译器自己做的指针。调用函数时,会一个个压参数进栈,并开辟栈帧。编译器在汇编时,就把this指针放到了里面。

2、空指针问题

加一个成员函数

public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void func()
	{
		cout << "func()" << endl;
	}
	Date* ptr = nullptr;
	ptr->func();
	ptr->Init(2023, 2, 3);

这里就很正常地运行了,打印出了func(),但是调用Init却会让程序崩溃。

成员函数不在对象里,当调用函数,会产生一个call指令,去在代码段里找函数地址,然后执行函数,不过func函数里没有对指针做什么,只是打印一行代码,所以没什么,对指针并没有解引用;Init做了什么?this指针接收到了空指针,这没问题,也就是调用的时候不崩溃,但是Init对空指针解引用了,所以崩了。如果ptr->_day,也会崩,因为也解引用了。这里也不能直接func(),而不带ptr,因为在C++入门(1)里提到过,编译器会在全局域里找,但是func不在,所以也不行。那如果(*ptr).func()呢?正常运行,虽然这是解引用,但编译器明白,你是在调用func这个函数,而这个ptr的实际作用就是传给this指针。在汇编里,ptr->func() 和 (*ptr).func()的代码是一样的。

3、C语言和C++简单对比

对比栈代码

C++

class Stack
{
public:
	void Init(int n)
	{
		a = (int*)malloc(sizeof(int) * capacity);
		if (nullptr == a)
		{
			perror("malloc申请空间失败");
			return;
		}
		capacity = n;
		size = 0;
	}

	void Push(int x)
	{
		a[size] = x;
	}

public:
	int* a;
	int size;
	int capacity;
};

C

typedef int DataType;
typedef int STDatatype;
typedef struct Stack
{
	STDatatype* a;
	int capacity;
	int top;
}ST;

void StackInit(ST* ps);
void StackDestroy(ST* ps);
void StackPush(ST* ps, STDatatype x);
void StackPop(ST* ps);
bool StackEmpty(ST* ps);
STDatatype StackTop(ST* ps);
STDatatype StackSize(ST* ps);

直接给出一些对比结果

CPP:
1、数据和方法都封装到类里面
2、控制访问方式。公有则可以访问,私有则不可以访问

C:
1、数据和方法是分离的
2、数据访问控制实自由的,不受控制(比如取栈顶,数据和方法分离那么就很自由)

结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/196014.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

美颜sdk人脸识别代码技术分析

很多人问过小编&#xff0c;什么样的美颜sdk才算好&#xff1f;对于这个问题&#xff0c;小编认为至少要符合以下几个特点。 1、稳定性强&#xff1b;2、识别精准&#xff1b;3、功能多样&#xff1b;4、集成容易&#xff1b;5、离线使用&#xff1b;6、支持多端&#xff1b;7、…

新手入门,深入解析 python lambda表达式

lambda 表达式是 Python 中的匿名函数。它接受任意数量的参数&#xff0c;并返回一个单个表达式的值。它的语法格式如下&#xff1a; lambda arguments: expression 文章目录lambda 函数原型解释lambda 函数用作其它参数lambda 函数高级的技巧多个参数返回多个值条件表达式嵌套…

java基础巩固-宇宙第一AiYWM:为了维持生计,编程语言番外篇之机器学习(项目预测模块总结:线性回归算法、逻辑回归分类算法)~整起

机器学习一、机器学习常见算法&#xff08;未完待续...&#xff09;1.算法一&#xff1a;线性回归算法&#xff1a;找一条完美的直线&#xff0c;完美拟合所有的点&#xff0c;使得直线与点的误差最小2.算法二&#xff1a;逻辑回归分类算法3.算法三&#xff1a;贝叶斯分类算法4…

PythonWeb开发基础(一)B/S开发和http协议

文章目录PythonWeb开发基础&#xff08;一&#xff09;B/S开发和http协议请求响应连接PythonWeb开发基础&#xff08;一&#xff09; B/S开发和http协议 推荐书籍&#xff1a;《HTTP权威开发指南》 前端&#xff1a;数据的格式化呈现&#xff0c;python中的format函数其实就…

【MyBatis】查询语句汇总

定义一个Car类:/*** 封装汽车相关信息的 pojo类*/ public class Car {// 数据库表当中的字段应该和pojo类的属性一一对应// 建议使用包装类, 这样可以防止null的问题private Long id;private String carNum;private String brand;private Double guidePrice;private String pro…

MATLAB入门——线性规划、非线性规划、多目标规划

4-1 线性规划_哔哩哔哩_bilibili 4-2 非线性规划_哔哩哔哩_bilibili 4-3 多目标规划_哔哩哔哩_bilibili 1.线性规划 有限条件下&#xff0c;最大收益 1. 例题 例题&#xff1a;张麻子既要攻碉楼又要追替身&#xff0c;他们一伙6人&#xff0c;总共1200发子弹;每有一人攻确…

【GCC】1: RTCP RR接收端生成

m79 代码。参考bytewoods 大神的以下文章:WebRTC 基于GCC的拥塞控制(上) WebRTC 基于GCC的拥塞控制(下)虽然可以拿到估算的带宽但是rtcp 总是malformed packet个 有必要带着问题跟进下整个过程 RR报文 基于丢包率的码率控制运行在发送端,依靠RTCP RR报文进行工作。* report b…

Vue2低代码平台搭建(一)

前言 大家好,我是L丶Y,这一次,我们来聊一聊前端低代码平台的构建。近些年来,随着Saas行业的高速发展,低代码的概念也逐渐流行了起来,而低代码产品也越来越多的出现在我们的身边,像国外的Mendix,国内的宜搭、苍穹、简道云等等,想通过这篇文章与大家对于前端低代码平台…

如何使用Baklib搭建企业内部wiki

Wiki 是一个协同著作平台或称开放编辑系统。我们可以用Wiki来建设帮助系统&#xff0c;知识库系统。国内公共wiki最著名就是百度百科&#xff0c;国外则是基维百科&#xff1b;Wiki最著名的例子之一是维基百科&#xff0c;它在MediaWiki上运行&#xff0c;任何拥有Web浏览器的人…

QT opencv 学习day02 基本数据结构 point Scalar Size Rect Mat 等等

1.point &#xff08;画点&#xff09; 1. 函数原型&#xff1a; //二维的点 typedef Point_<int> Point2i; typedef Point_<int64> Point2l; typedef Point_<float> Point2f; typedef Point_<double> Point2d; typedef Point2i Point;//三维的点…

EasyExcel 实现 批量生成多sheet多Excel打包zip下载

目录说明需求场景实现1、准备一个excel模板2、把整个excel模板放在resources里面3、重点代码效果图说明 需求场景 导出学校中高年级的学生信息&#xff0c;根据班级名称分组&#xff0c;一个班级一个excel导出&#xff0c;如果多个excel需要打包成zip压缩包下载&#xff0c;一…

Linux应用编程-音频应用编程-语音转文字项目

文章目录前言Linux语音识别alsa-lib简介&#xff1a;安装alsa-lib库&#xff1a;API调用录音相关概念样本长度&#xff08;Sample&#xff09;声道数&#xff08;channel&#xff09;帧&#xff08;frame&#xff09;周期&#xff08;period&#xff09;采样率&#xff08;Samp…

springboot整合JSR303参数校验与全局异常处理

一、前言 我们在日常开发中&#xff0c;避不开的就是参数校验&#xff0c;有人说前端不是会在表单中进行校验的吗&#xff1f;在后端中&#xff0c;我们可以直接不管前端怎么样判断过滤&#xff0c;我们后端都需要进行再次判断&#xff0c;为了安全。因为前端很容易拜托&#…

[面试八股] Mysql

1、Mysql中的索引类型 &#xff08;1&#xff09;普通索引&#xff08;2&#xff09;唯一索引&#xff08;3&#xff09;主键索引&#xff08;4&#xff09;组合索引&#xff08;5&#xff09;全文索引 缺点 1、虽然索引大大提高了查询速度&#xff0c;同时却会降低更新表的速…

Mysql高级部分学习笔记(二)——事务锁

一、buffer pool 1.1 缓冲池&#xff08;buffer pool&#xff09; 简介&#xff1a;InnoDB是基于磁盘存储的&#xff0c;并将其中的数据按页的方式进行管理。因此InnoDB可视为基于磁盘的数据库系统。由于CPU的速度和磁盘IO速度的巨大鸿沟&#xff0c;需要**缓冲池(buffer poo…

windows下通过uiAutomation技术获取ui元素

最近接个需求&#xff0c;要求获取 windows 下 ui 元素&#xff0c;经一番搜索后了解到可通过工具 UISpy.exe 或 inspect.exe 来进行查看。以软件 davinci resolve 为例&#xff1a; 右侧即 UISpy 工具&#xff0c;根据内容可以看出已捕获到 davinci 界面的各属性及对应值。而 …

ItextPdf 字体显示差异分析与处理

ItextPdf 同span下字体显示差异分析与处理 在文章itext7 字体问题解答与相应源代码分析 中是分析了框架的字体设置与相关代码&#xff0c;在本篇文章里将对其生效效果进行分析和相关问题进行处理&#xff08;可持续更新&#xff0c;问题请留言&#xff09; 问题一 问题说明&…

将无风险资产与两种风险资产进行组合

目录 最优风险资产组合。 计算权重的公式。 应用。 最优风险资产组合。 曲线 AB 是两种风险资产的权衡取舍线。 A 点为资产组合中仅有风险资产 1 的情况。将 O 点与 A 点相连&#xff0c;便得到无风险资产与单个风险资产的权衡取舍线。 实际上&#xff0c;曲线 AB 上任一点…

【青训营】分布式理论初探

本文内容总结自 字节跳动青年训练营 第五届后端组 分布式理论初探 一、概述 分布式系统是计算机程序的集合&#xff0c;这些程序利用横跨多个独立计算节点的计算资源实现共同目标&#xff0c;可分为分布式计算、分布式存储、分布式数据库。 其优势是&#xff1a;去中心化、…

ESP32设备驱动-TEA5767收音机模块驱动

TEA5767收音机模块驱动 1、TEA5767介绍 TEA5767HN 是一款用于低压应用的单芯片电子调谐 FM 立体声收音机,具有完全集成的中频 (IF) 选择性和解调功能,频率范围从76—108MHZ自动数字调谐。 该收音机完全无需调整,高灵敏度,高稳定性,低噪音,收音模块。只需要最少的小型低…