C++之类和对象(上)

news2024/11/20 11:44:25

目录

1.面向过程和面向对象初步认识

2.类的引入 

3.类的定义

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

4.1访问限定符

4.2 类的两种定义方式

第一种:

第二种:

4.3封装

5.类的实例化

6.类对象模型 


1.面向过程和面向对象初步认识

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

2.类的引入 

C语言中,结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数

struct stack
{
	int* a;
	int size;
	int capacity;
};
void Init()
{
	//...
}
void Destory()
{
	//...
}
int main()
{
	stack st;
	return 0;
}

 这是正常情况下我们去建立一个栈的代码(省略了一部分)

在C++中,我们则是优化使用了类去实现栈,更加便捷

我们可以直接去定义新的栈

struct stack st1;
stack st2;

同时,我们还可以把我们所需要的栈的函数去定义到我们的结构体中

using namespace std;
struct stack
{
	int* a;
	int size;
	int capacity;
	void Init(int n = 4)
	{
		a = (int*)malloc(sizeof(int) * n);
		if (a == nullptr)
		{
			perror("malloc fail");
			return;
		}
		//...
		size = 0;
		capacity = n;

	}
	void Destory()
	{
		//...
	}
	void Push(int x)
	{
		a[size++] = x;
	}
};
int main()
{
	//stack st;
	stack st1;
	st1.Init();
	st1.Push(1);
	st1.Push(2);
	st1.Push(3);
	st1.Push(4);
	return 0;
}

如以上代码

这里的st1就是一个对象

3.类的定义

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

class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号。 类中的元素称为类的成员:类中的数据称为类的属性或者成员变量; 类中的函数称为类的方法或者成员函数

我们可以简单定义一个日期,也就是年月日

class Data
{
private:
	int _year;
	int _month;
	int _day;
};

C++中一般在定义变量中都会在前边加上一个_去区分

然后我们再加一个函数去令他完善一下

class Data
{
public:
	void Init(int year = 2024,int month = 1,int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Data d1;
	d1.Init(2024, 4, 6);
	return 0;
}

这样我们就完成了

这里就会有人问了,这里的public和private又是什么?

这里就涉及到我们另外一个知识点:类的访问限定符及封装

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

4.1访问限定符

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

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

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

 所以用通俗易懂的话去讲就是:

private里面的基本都是存储的变量,无法去直接访问并改变,publi里面的存储的是函数,可以直接去访问并做出一定的编译

所以理解这些后,刚才的日期代码才能够去充分理解

class Data
{
public:
	void Init(int year = 2024,int month = 1,int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Data d1;
	d1.Init(2024, 4, 6);
	return 0;
}

4.2 类的两种定义方式

在C++中定义类时,主要有两种方式:在单个文件中定义整个类(包括成员变量和成员函数),或者将类的声明和定义分别放在不同的文件中(声明定义分离)。下面将详细讨论这两种方式

第一种:

声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理

using namespace std;
struct stack
{
	int* a;
	int size;
	int capacity;
	void Init(int n = 4)
	{
		a = (int*)malloc(sizeof(int) * n);
		if (a == nullptr)
		{
			perror("malloc fail");
			return;
		}
		//...
		size = 0;
		capacity = n;

	}
	void Destory()
	{
		//...
	}
	void Push(int x)
	{
		a[size++] = x;
	}
};

第二种:

类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::

.h文件:

class stack
{
public:
	void Init(int n = 4);
	void Push(int x);
private:
	int* a;
	int size;
	int capacity;
};

.cpp文件:

void stack::Init(int n)
{
	a = (int*)malloc(sizeof(int) * n);
	if (a == nullptr)
	{
		perror("malloc fail");
		return;
	}
	capacity = n;
	size = 0;
}
void stack::Push(int x)
{
	//...
}

在.cpp文件中,我们不要直接去定义Init,如果直接定义会报错 

所以要在Init前边加上stack::去表明,这是这个是属于stack类域的(也就是类的作用域)

同时也要注意:传参时,我们只需要在头文件中去设置半参省或者全参省,在源文件.cpp中只需要传递所需要的参数即可,也就是int  n

 类的作用域也是影响了搜索规则,比如下面两个类,栈和队列都有init和push函数:


class stack
{
public:
	void Init(int n = 4);
	void Push(int x);
};
class queue
{
public:
	void Push(int x);
};

如果没有域的存在,就会出现冲突

所以,类本身就是一种域

4.3封装

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

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

封装本质上是一种管理:我们如何管理兵马俑呢?比如如果什么都不管,兵马俑就被随意破坏了。那么我们 首先建了一座房子把兵马俑给封装起来。但是我们目的全封装起来,不让别人看。所以我们开放了售票通 道,可以买票突破封装在合理的监管机制下进去参观。类也是一样,我们使用类数据和方法都封装到一下。 不想给别人看到的,我们使用protected/private把成员封装起来。开放一些共有的成员函数对成员合理的访 问。所以封装本质是一种管理。

封装的优势:

  1. 安全性:通过隐藏其内部状态,对象不会因为外部代码的直接访问而处于不一致的状态
     

  2. 简化接口:对象提供的公共方法可以是简单的接口,使用者无需了解实现细节即可使用对象
     

  3. 降低复杂性:将数据和操作数据的代码封装在一起有助于减少系统的复杂性
     

  4. 可维护性和可扩展性:封装使得修改和增加功能变得简单,因为修改的影响局限于单个对象内部,不会波及整个系统
     

  5. 重用性:通过封装,可以使对象更加通用,易于在不同场景下复用

5.类的实例化

用类类型创建对象的过程,称为类的实例化

class Data
{
public:
	void Init(int year = 2024,int month = 1,int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

思考一下,在这个代码中,int _year;  int _month;  int _day;这是声明还是定义呢?

定义和声明的本质区别是是否开辟一块空间

class Data
{
public:
	void Init(int year = 2024,int month = 1,int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Data d1;
	//d1.Init(2024, 4, 6);
	return 0;
}

这里的Data d1;这才是定义

在这里,我们不能直接对 Data::Init进行直接访问,也无法对year,month以及day进行直接访问,因为这里的year,month以及day只是声明不是定义

但是我们可以对d1的变量进行访问 

而这一步,Data d1;这就是类的实例化

类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它

  1. 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它
  2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
  3.  做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什 么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占 用物理空间 

6.类对象模型 

类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大 小?

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

 上面类的大小是多少字节?

结构体内存对齐规则:

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

我们利用sizeof计算一下

 12字节

这个12字节怎么算的呢?

如果去除掉函数的话,一共3个int元素变量,这样的话确实是12字节

是不是函数不算呢?

我们去除一下函数看一看

还是12字节

所以由此可知,这与类成员的存储结构有关,与函数无关

 这里定义了一个d1,我们在定义一个d2看一看

转到编译码中可以看到,两个函数的地址相同

所以猜测一下,类的对象模型应该是什么样的??? 

猜测一:对象中包含类的各个成员

缺陷:每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。 

猜测二:只保存成员变量,成员函数存放在公共的代码段

 

 每个成员的函数的地址都是一样的,在公共区域存放函数的代码更加的合理

class A2 {
public:
   void f2() {}
};

看一下,这个类的大小是多少?

大小为一

为什么呢?

原因是:

在C++中,类的大小是由其数据成员决定的。如果一个类没有数据成员,其大小通常不会是0,因为语言标准确保每个对象都必须有一个独一无二的地址,以便能够区分不同的对象。即使一个类没有任何数据成员,编译器也会给对象分配至少一个字节的大小,以保证对象有独立的地址 

所以对于A2这个类域,虽然里面没有数据成员,只有一个函数f2,但编译器也会给一个字节的空间

class fun {
public:
	void Print()
	{
		cout << "被调用" << endl;
	}
};
int main()
{
	fun a1;
	fun* p1 = &a1;
	p1->Print();
	fun* p = nullptr;
	p->Print();
	return 0;
}

再看一下这个代码

把p设置为空指针,这里的print还会被调用吗?

最终结果仍是被调用了

为什么呢?

这里的Printf函数并不在指针指向的空间里面,而这里的p1,p2指向的是对象,对象里面没有函数的地址,虽然有箭头,但是并没有进行解引用 

 

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

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

相关文章

华为汽车的“计算+通信”电子电气架构

文章目录 整车结构 硬件平台 软件平台 总结展望 整车EEA&#xff08;电子电气架构&#xff09;&#xff0c;按照博世提出的演进路径&#xff0c;大致可以划分为四个阶段&#xff1a;分布式模块阶段、区域控制阶段、中央计算阶段、云计算阶段。示例如下&#xff1a; 本文选取…

Java8 进阶

Java8 进阶 文章目录 Java8 进阶什么是函数式接口&#xff1f;public interface Supplierpublic interface Consumerpublic interface Predicatepublic interface FunctionJava8 特性总结&#xff1a;一、Function<T, R>二、Consumer<T>三、Supplier<T>四、P…

BUUCTF:BUU UPLOAD COURSE 1[WriteUP]

构造一句话PHP木马 <?php eval(system($_POST[shell])); ?> 利用eval函数解析$shell的值使得服务器执行system命令 eval函数是无法直接执行命令的&#xff0c;只能把字符串当作php代码解析 这里我们构造的木马是POST的方式上传&#xff0c;那就用MaxHacKBar来执行 …

分布式锁实战

4、分布式锁 4.1 、基本原理和实现方式对比 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁&#xff0c;只要大家使用的是同一把锁&#xff0c;那么我们就能锁住线程&#xff0c;不让线程进行&#x…

springBoot--阿里云短信验证

阿里云短信验证 前言阿里云短信服务免费领取100条短信服务1、开通短信服务2、申请签名3、申请模板4、通过子用户获取账号的AccessKey ID 和AccessKey Secret5、使用教程 前言 在我们平时登录中短信验证吗验证在当今是必不可少的&#xff0c;下面是基于阿里云开发的短信验证操作…

【Qt 学习笔记】详解Qt中的信号和槽

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 详解Qt中的信号与槽 文章编号&#xff1a;Qt 学习笔记 / 12 文章目录…

【数据结构】ArrayList详解

目录 前言 1. 线性表 2. 顺序表 3. ArrayList的介绍和使用 3.1 语法格式 3.2 添加元素 3.3 删除元素 3.4 截取部分arrayList 3.5 其他方法 4. ArrayList的遍历 5.ArrayList的扩容机制 6. ArrayList的优缺点 结语 前言 在集合框架中&#xff0c;ArrayList就是一个…

代码随想录第19天

654. 最大二叉树 已解答 中等 相关标签 相关企业 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀…

Mac 配置 Aria2

文章目录 1. Aria2 安装1.1 安装 brew1.2 安装 Aria2 2. 配置 Aria22.1 创建配置文件 aria2.conf 和空对话文件 aria2.session2.2 编辑配置文件 aria2.conf 3. 开机启动设置3.1 创建用户启动文件3.2 管理自启动项 4. 配置 BT tracker 自动更新4.1 XIU2/TrackersListCollection …

通义灵码-ai编码

https://developer.aliyun.com/topic/lingma/activities/202403?taskCode14508&recordIdb1ef3ba27250a5818b1b6ffe418af658#/?utm_contentm_fission_1 「通义灵码 体验 AI 编码&#xff0c;开 AI 盲盒」

sourcetree提交代码出现闪退报错(已解决)

当我在sourcetree提交代码时&#xff0c;点击提交按钮出现闪退关闭&#xff0c;并弹出下面的报错框&#xff0c;报错的图片如下&#xff1a; 那么经过了解&#xff0c;出现这样的报错原因是&#xff0c;git的提交时无法定位提交的人是谁&#xff0c;导致无法提交 那么解决的方…

Allavsoft for Mac v3.27.0.8852注册激活版 优秀的视频下载工具

Allavsoft for Mac是一款功能强大的多媒体下载和转换工具&#xff0c;支持从各种在线视频网站和流媒体服务下载视频、音频和图片。它具备批量下载和转换功能&#xff0c;可将文件转换为多种格式&#xff0c;以适应不同设备的播放需求。此外&#xff0c;Allavsoft还提供视频编辑…

ARM v8 Cortex R52内核 02 程序模型 Programmers Model

ARM v8 Cortex R52内核 02 程序模型 Programmers Model 2.1 关于程序模型 Cortex-R52处理器实现了Armv8-R架构。这包括&#xff1a; 所有的异常级别&#xff0c;EL0-EL2。 每个异常级别下的AArch32执行状态。 T32和A32指令集&#xff0c;其中包括&#xff1a; 浮点运算。 …

电子商务平台中大数据的应用|主流电商平台大数据采集API接口

(一)电商平台物流管理中大数据的应用 电商平台订单详情订单列表物流信息API接口应用 电子商务企业对射频识别设备、条形码扫描设备、全球定位系统及销售网站、交通、库存等管理软件数据进行实时或近实时的分析研究,提高物流速度和准确性。部分电商平台已建立高效的物流配送网…

Ruoyi-vue-pro Vue + nginx 二级目录部署到云服务器

http://www.your-server.com/ 这是一级目录&#xff0c;由于项目多&#xff0c;一般会通过二级域名http://oa.your-server.com/或二级目录http://www.your-server.com/oa来发布&#xff0c;本篇记录一下二级目录发布。先看效果 1、router/index.js配置base export default new …

Open CASCADE学习|在给定的TopoDS_Shape中查找与特定顶点 V 对应的TopoDS_Edge编号

enum TopAbs_ShapeEnum{TopAbs_COMPOUND,TopAbs_COMPSOLID,TopAbs_SOLID,TopAbs_SHELL,TopAbs_FACE,TopAbs_WIRE,TopAbs_EDGE,TopAbs_VERTEX,TopAbs_SHAPE}; 这段代码定义了一个名为 TopAbs_ShapeEnum 的枚举类型&#xff0c;它包含了表示不同几何形状类型的常量。这些常量通常…

5G网络架构及技术(二):OFDM一

ToDo: 等把这些讲义看完后得单开一个文章整理思维导图   该部分由于内容比较重要&#xff0c;OFDM是5G物理层的基础&#xff0c;但学习时直接跳到5G OFDM去看它的那些参数设置感觉没什么意义&#xff0c;还得从发展的角度进行学习&#xff0c;先从最先用到OFDM的WiFi协议开始…

最新版两款不同版SEO超级外链工具PHP源码

可根据个人感觉喜好自行任意选择不同版本使用&#xff08;版V1或版V2&#xff09; 请将zip文件全部解压缩即可访问&#xff01; 源码全部开源&#xff0c;支持上传二级目录访问 #已更新增加大量高质量外链&#xff08;若需要增加修改其他外链请打开txt文件&#xff09; #修…

隐私计算实训营学习八:隐语SCQL的开发实践

文章目录 一、SCQL使用集成最佳实践1.1 SCQL使用流程1.2 SCQL部署1.3 SCQL使用示例 二、SCQL工作原理三、使用SecretNote上手体验SCQL 一、SCQL使用集成最佳实践 1.1 SCQL使用流程 SCQL使用&#xff1a; SCQL 开放 API 供⽤户使⽤/集成。可以使⽤SCDBClient上⼿体验(类似与My…

基于R、Python的Copula变量相关性分析及AI大模型应用

在工程、水文和金融等各学科的研究中&#xff0c;总是会遇到很多变量&#xff0c;研究这些相互纠缠的变量间的相关关系是各学科的研究的重点。虽然皮尔逊相关、秩相关等相关系数提供了变量间相关关系的粗略结果&#xff0c;但这些系数都存在着无法克服的困难。例如&#xff0c;…