C++之类和对象(上)

目录

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.mzph.cn/news/795851.shtml

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

相关文章

【ARM 嵌入式 C 文件操作系列 20 -- 文件删除函数 remove 详细介绍】

请阅读【嵌入式开发学习必备专栏 】 文章目录 文件删除函数 remove 文件删除函数 remove 在 C 语言中&#xff0c; 可以使用 remove 函数来删除一个文件&#xff0c;但在删除之前 可能想确认该文件是否存在。 可以使用 stat 函数来检查文件是否存在。 以下是如何实现这个功能…

出门一笑, “栈” 落江横 (Java篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

03-自媒体文章发布

自媒体文章发布 1)自媒体前后端搭建 1.1)后台搭建 ①&#xff1a;资料中找到heima-leadnews-wemedia.zip解压 拷贝到heima-leadnews-service工程下&#xff0c;并指定子模块 执行leadnews-wemedia.sql脚本 添加对应的nacos配置 spring:datasource:driver-class-name: com…

23年蓝桥杯省赛 动态规划DP

动态规划 就是:给定一个问题&#xff0c;我们把它拆成一个个子问题&#xff0c;直到子问可以直接解决。然后把子问题的答案保存起来&#xff0c;以减少重量计算&#xff0c;再根据子问题答察反推&#xff0c;得出问解的一种方法。 题目&#xff1a; 这天&#xff0c;一只蜗牛…

QT串口接收数据并进行波形显示(含源码)

**使用QT在串口调试助手基础上实现波形显示&#xff08;含源码&#xff09; 评论比较多留言需要源码的&#xff0c;逐个发邮箱比较麻烦也不能及时回复&#xff0c;现将源码上传至链接&#xff08;无需积分下载&#xff09;https://download.csdn.net/download/m0_51294753/877…

mysql 8.0 常用函数大全总结,并列出实例

MySQL 8.0提供了丰富的内置函数&#xff0c;这些函数可以大致分为几个类别&#xff1a;字符串函数、数值函数、日期和时间函数、比较函数、逻辑函数、控制流函数等。以下是20个常用的MySQL函数及其简单的使用示例&#xff1a; 1. **CONCAT()**: 字符串连接函数。 - 示例&am…

设计一个可扩展的Python Web框架:并发、性能与安全性考量

设计一个可扩展的Python Web框架&#xff1a;并发、性能与安全性考量 一、引言 随着Web应用的日益复杂和需求的不断增长&#xff0c;一个可扩展的Web框架变得至关重要。在Python生态系统中&#xff0c;虽然存在诸多优秀的Web框架&#xff0c;但设计一个符合自身需求且具备高度…

云服务器4m带宽是什么意思?

云服务器配置4M带宽是什么意思&#xff1f;4M代表该台云服务器的网络传输速度为4Mbps&#xff0c;一般指该台云服务器的公网出方向带宽&#xff0c;即从云服务器下载的公网带宽&#xff0c;4M带宽下载速度为512KB/秒&#xff0c;云服务器吧yunfuwuqiba.com整理常见的云服务器公…

Java之过滤器Filter、拦截器Interceptor与面向切面AOP

Java之过滤器Filter、拦截器Interceptor与面向切面AOP Filter的使用 Component WebFilter(urlPatterns {"/*"}) public class CustomFilter implements Filter {Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain cha…

cJSON(API的详细使用教程)

我们今天来学习一般嵌入式的必备库&#xff0c;JSON库 1&#xff0c;json和cJSON 那什么是JSON什么是cJSON&#xff0c;他们之间有什么样的关联呢&#xff0c;让我们一起来探究一下吧。 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&…

C和C++内存管理

目录&#xff1a; 一&#xff1a;C和C内存分布 二&#xff1a;C动态内存管理方式 三&#xff1a;C动态内存管理方式 四&#xff1a;operator new与operator delete函数 五&#xff1a;new和delete的实现原理 六&#xff1a;定位new表达式(placement-new) 七&#xff1…

使用YOLOv8训练自己的【目标检测】数据集

文章目录 1.收集数据集1.1 使用开源已标记数据集1.2 爬取网络图像1.3 自己拍摄数据集1.4 使用数据增强生成数据集1.5 使用算法合成图像 2.标注数据集2.1确认标注格式2.2 开始标注 3.划分数据集4.配置训练环境4.1获取代码4.2安装环境 5.训练模型5.1新建一个数据集yaml文件5.2预测…

了解IP地址的基本概念和修改步骤

在数字化时代&#xff0c;IP地址作为网络设备的唯一标识&#xff0c;其重要性不言而喻。无论是为了提升网络性能&#xff0c;还是出于隐私保护的需求&#xff0c;修改IP地址都是网络使用者可能遇到的操作。虎观代理将详细介绍如何修改IP地址&#xff0c;并探讨在修改过程中需要…

python+flask+django文献文件资料搜索系统

后端&#xff1a;python 前端&#xff1a;vue.jselementui 框架&#xff1a;django/flask Python版本&#xff1a;python3.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm 本系统在设计过程中&#xff0c;很好地发挥了该开发方式的优…

刷题DAY45 | 70-爬楼梯(进阶) LeetCode 322-零钱兑换 279-完全平方数

70 爬楼梯&#xff08;进阶&#xff09; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬至多m (1 < m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 注意&#xff1a;给定 n 是一个正整数。 输入描述 输入共一行&#xff0c;包含两个正整数&…

120.单例模式(C++设计模式)

一、什么是单例模式 单例模式是一种创建型设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取这个实例。 在C中实现单例模式通常会遵循以下步骤&#xff1a; 私有构造函数&#xff1a;确保单例类的构造函数是私有的&#xff0c;这样外部就…

例47:键盘事件演示

建立一个EXE工程&#xff0c;在默认窗体上放一个Image框和一一个text框。在text的按键事件中输入代码&#xff1a; Function Form1_Text1_WM_KeyDown(hWndForm As hWnd, hWndControl As hWnd,nVirtKey As Long, lKeyData As Long) As LongIf nVirtKey VK_SPACE ThenImage1.Pi…

【题单】 洛谷哈希题单

这里写目录标题 updata普及-普及/提高-普及/提高提高/省选-省选/NOI−NOI/NOI/CTSC updata 2024.04.06 15:35 发布此文章 普及- P1102 A-B 数对 P1211 [USACO1.3] 牛式 Prime Cryptarithm P2957 [USACO09OCT] Barn Echoes G P3370 【模板】字符串哈希 P4305 [JLOI2011] 不重…

最小花费

题目描述 在 n 个人中&#xff0c;某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费&#xff0c;请问 A 最少需要多少钱使得转账后 B 收到 100 元。 输入描述 第一行输入两个正整数 n,m&#…

基础算法06|反转链表

206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { th…