C++类和对象(上)

文章目录
- 🦍1. 面向过程和面向对象
 - 🦧2. 类的引入
 - 🐶3. 类的定义
 - 🦮4. 类的访问控制和封装
 - 🍖4.1 访问限定符
 - 🍖4.2 封装
 
- 🐩5. 类的作用域
 - 🐅6. 类的实例化
 - 🐄7. 类的大小计算
 - 🦌8. this指针
 - 🥕8.1 引子
 - 🥕8.2 this指针特性
 
🦍1. 面向过程和面向对象
C语言是一门面向过程的编程语言,面向过程更注重于解决问题的步骤和流程。而C++是基于面向对象的,关注的是对象之间的交互,。我们将数据和相关的功能封装在一起,形成对象。每个对象都有自己的属性(数据)和方法(功能)。
以做一道青椒肉丝来说
我们需要厨师、青椒、肉丝、锅、铲、油、盐、老抽等物品,然后再准备烹饪。先放油,油热再放肉丝,肉丝炒的差不多之后再放青椒,然后再放入盐、老抽,最后装盘,这些就属于面向过程;
在面向对象编程中,我们会将青椒肉丝看作一个对象,并定义该对象的属性和方法。
对象:青椒肉丝
- 属性:青椒、肉片、调味料等
 - 方法:准备食材、炒菜、调味、出锅等
 我们可以创建一个青椒肉丝对象,并调用对象的方法来完成烹饪过程。每个方法内部可以封装相应的逻辑和操作。
例如,调用青椒肉丝对象的"准备食材"方法,内部会包含切青椒、切肉片和腌制肉片的操作。调用"炒菜"方法时,内部会进行炒肉片和炒青椒的步骤。通过调用对象的方法,我们可以按照特定的顺序和逻辑来完成整个烹饪过程。
面向过程适用于简单的、直线式的问题,或者强调步骤和算法的场景。面向对象适用于复杂的、需要模拟真实世界的问题,或者强调对象之间关系和交互的场景。现在市面上主流的编程语言基本上都是面向对象:C++、Java、Python等。
🦧2. 类的引入
在C语言中,结构体就可以封装多个对象用来描述一些负责的事物。在C++中,将结构体升级成了类,不仅可以定义变量,还可以定义函数。
struct Stack
{//方法(函数)void Init(int defaultCapacity = 4){a = (int*)malloc(sizeof(int) * 4);if (nullptr == a){perror("malloc fail");exit(-1);}capacity = defaultCapacity;top = 0;}void Push(int x){//...;}void Destory(){free(a);a = nullptr;top = capacity;}//...//成员变量(属性)int* a;int top;int capacity;
};
int main()
{//兼容C语言struct Stack s1;//C++Stack st2;st2.Init();st2.Push(1);st2.Push(2);st2.Destory();return 0;
}
 
🐶3. 类的定义
虽然struct可以定义类,但是为了区分C语言,C++更喜欢用class来定义类。
class定义为类的关键字,后面紧跟类名,{}为类的主体。
class ClassName {
private:// 成员变量(私有)DataType memberVariable1;DataType memberVariable2;...public:// 构造函数ClassName();  // 默认构造函数ClassName(parameter1, parameter2, ...);  // 带参数的构造函数// 成员函数(公有)ReturnType memberFunction1(parameter1, parameter2, ...);ReturnType memberFunction2(parameter1, parameter2, ...);...
};
 
- 使用 
class关键字来定义类,后面紧跟着类名(通常遵循命名约定,使用驼峰命名法)。 - 在类定义中,我们可以声明成员变量和成员函数。
 - 成员变量是类的数据成员,表示类的特征或状态。它们在私有部分(
private)进行声明,只能在类的内部访问。 - 构造函数是一种特殊的成员函数,用于创建和初始化类的对象。在示例中,我们展示了默认构造函数和带参数的构造函数的定义。构造函数的名称与类名相同,没有返回类型。
 - 成员函数是类的行为和操作。它们在公有部分(
public)进行声明,并可以包含任意的参数和返回类型。成员函数可以访问类的成员变量,执行特定的操作。 
类也可以声明和定义分离:
类里面定义的函数,默认是内联函数,但具体也还是编译器决定是否为内联函数。
🦮4. 类的访问控制和封装
🍖4.1 访问限定符
当使用class来定义时,程序编译报错,我们定义的这些方法,无法访问。

这些是因为C++中类进行了封装和访问控制,用三种修饰符来实现:
private(私有): 成员被声明为private时,它们只能在类的内部访问。私有成员对于类的外部是不可见的,外部代码无法直接访问它们。public(公有): 成员被声明为public时,它们可以在类的内部和外部被访问。公有成员对外部代码可见,可以通过类的对象访问和操作。protected(保护): 成员被声明为protected时,它们与私有成员类似,只能在类的内部和派生类中访问。受保护成员对于外部代码是不可见的,但可以在派生类中被继承和访问。
访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。
class如果不设置访问限定符,默认为private;
struct因为要兼容C语言,所以默认为public。
🍖4.2 封装
面向对象的三大特性:封装、继承、多态。
在面向对象的封装中,类是封装的基本单位,类封装了数据成员和成员函数。封装的主要目的是将相关的数据和操作组织在一起,形成一个独立的实体,对外部隐藏其内部实现细节,只提供公共接口。
比如说,我们国家的博物馆里面的展品,大部分都会设置阻隔,我们观众可以参观,但是无法直接接触到这些展品。这在一定程度上保护了这些展品,同时也规范了观众的行为,满足了观众的基本需求。
在程序中,封装也是如此,通过将数据和操作封装在一起,实现了数据的隐藏和保护。
🐩5. 类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域
class MyClass {
public:int publicMember;  // 公有成员void PrintInfo();
private:int privateMember;  // 私有成员protected:int protectedMember;  // 受保护成员
};//指定PrintInfor属于MyClass这个类域
void MyClass::PrintInfo()
{cout << "MyClass" << endl;
}int main() {MyClass myObject;myObject.publicMember = 10;  // 可访问公有成员myObject.PrintInfo();// 以下代码将导致编译错误,无法访问私有成员和受保护成员// myObject.privateMember = 20;// myObject.protectedMember = 30;return 0;
}
 
🐅6. 类的实例化
类的实例化是指根据类的定义创建一个具体的对象,使其具备类所定义的属性和行为。
我们定义一个类:
class Person
{
public:void showInfo(){cout << "xxx" << endl;//...}
private:char* _name;char* _sex;int _age;
};
 
这里并没有实例化↑,只是描述出了一个人应该具备的基本属性。
//直接声明对象变量静态实例化对象
Person P1;Person P2;
 
实例化对象 ↑ P1、P2。
类就好比一张食谱,食谱上面有许多道菜的做法,但没有实际的菜存在,所以定义出一个类并没有分配实际的内存空间来存储它。
我们将其实例化,就是把这道菜做出来呈现在我们眼前,它实际存在,占据物理空间。
🐄7. 类的大小计算
class MyClass
{
public:void Print(){cout << "MyClass" << endl;}
private:int a;
};int main()
{cout << sizeof(MyClass) << endl;return 0;
}
 
类中既有成员变量,又有成员函数,那么这在计算内存的时候,是如何计算的呢?
// 类中既有成员变量,又有成员函数
class A1 {
public:void f1() {}
private:int _a;
};// 类中仅有成员函数
class A2 {
public:void f2() {}
};// 类中什么都没有---空类
class A3
{};int main()
{cout << sizeof(A1) << endl;cout << sizeof(A2) << endl;cout << sizeof(A3) << endl;
}
 
执行该程序得出:
4
1
1
我们发现,类的大小,计算的是该类中的成员变量之和,并没有算入函数;而没有成员变量或者是空类,大小为1byte。
这是因为成员函数是共享给所以该类的使用对象使用的代码,并不直接存储在该类中。
打个比方:
假设我们有一个小区,里面有很多房屋,每个房屋都有自己的卧室、客厅、厨房等空间,这些就代表着类对象中的数据成员。
但是小区里面会有公共的篮球场、公园等空间,这些并没有算在自己房子的大小之内,属于公共区域,供小区居民共享使用的。
在这个比喻中,房屋可以类比为类对象的数据成员,而篮球场可以类比为类的成员函数。房屋占用实际的空间,我们说房子多大就是自己的房子有多少个平方,而篮球场作为公共设施,只是为小区居民提供服务,不会计算在房子的大小中。
类成员计算大小时,也遵循内存对齐规则——内存对齐。
🦌8. this指针
🥕8.1 引子
我们定义一个人的类Person
class Person
{
public:void Init(const std::string& n, const std::string& sex, int age){_name = n;_sex = sex;_age = age;}void Print(){cout << _name << " " << _sex << " " << _age << endl;}
private:std::string _name;std::string _sex;int _age = 0;
};int main()
{Person p1, p2;p1.Init("zhangsan", "man", 21);p2.Init("cuihua", "woman", 20);p1.Print();p2.Print();
}
 
Person类中,有Init和Print两个成员函数,我们刚才说到,成员函数并没有算入类的空间中,那当p1调用Init和Print的时候,这两个函数是怎么知道是p1呢?
C++中,给每个非静态成员函数,增加了一个隐藏的指针参数,该指针指向了当前对象,函数体的所以成员变量的操作都是通过指针去访问的。这个对于我们用户来说是透明的,不需要我们来传递,编译器自动完成。
🥕8.2 this指针特性
-  
只能在成员函数内部使用

 -  
this指针是成员函数的第一个隐藏指针形参,由编译器自动传递由于
this指针是一个形参,所以应该就和普通的参数一样存放在栈区里面,但是有些编译器会对其进行优化。以VS2022为例,我们发现
this指针存放在了rcx中(rcx是x86架构中通用的寄存器之一)。
 -  
this指针是一个常量指针,它指向当前对象并不能被修改,也不能被显式地赋值给其他指针变量。它始终指向当前对象,无法指向其他对象。 
有了这些知识储备,我们来看一下,这段程序的运行结果是什么?
class A
{
public:void PrintA(){cout << "PrintA()" << endl;}
private:int _a;
};
class B
{
public:void PrintB(){cout << _b << endl;}
private:int _b;
};
int main()
{A* pa = nullptr;B* pb = nullptr;pa->PrintA();pb->PrintB();return 0;
}
 
运行发现,控制台上打印出了PrintA(),随后程序运行崩溃了。
这是因为A和B在调用各自的Print()成员函数时,没有发生解引用,因为Print()的地址不在对象中,A和B作为实参传递给了this指针。但是进入Print()函数后,由于A和B都是空,所以this指针也为空,A没有对齐解引用,而B访问了它的成员_b,本质上就是this->_b,对空指针解引用,所以会崩溃。
我们需要知道类是面向对象编程的核心概念,类是对象的蓝图,定义了对象的属性和行为,而对象则是根据类的定义创建的实体。
 那本期的分享就到这里啦,如果有帮助的话,希望三连支持一下,我们下期再见,如果还有下期的话。
相关文章:
C++类和对象(上)
文章目录 🦍1. 面向过程和面向对象🦧2. 类的引入🐶3. 类的定义🦮4. 类的访问控制和封装🍖4.1 访问限定符🍖4.2 封装 🐩5. 类的作用域🐅6. 类的实例化🐄7. 类的大小计算&a…...
JavaScript 数据透视表 DHTMLX Pivot Crack
DHTMLX Pivot JavaScript 数据透视表 - 强大的数据汇总和报告 使用我们的高速 JavaScript/HTML5 Pivot 组件可视化您的复杂数据,从而提高您的商业智能。 它可以帮助您以方便的方式汇总大型数据集。 主要特征 纯 JavaScript 库,可轻松与任何服务器端集成…...
QT链接库设置
以windows 平台为例,在.pro 文件中: 1 增加 INCLUDEPATH <头文件路径> DEPENDPATH <头文件路径> 2 LIBS -L<库目录路径> -l<库得名字> 3 设置MT、MTD、MD、MDD运行时库 win32:CONFIG(debug, debug|release): { QMAKE_CFLAGS_…...
零点起飞学Android——期末考试课本复习重点
目录 第一章 认识Android第二章 Android常见界面布局第三章 Android常用基本控件第四章 Android 高级控件第五章 Android菜单和对话框 第一章 认识Android 1. Android 界面设计被称为______。 答案:布局 2. Android中常见的布局包括______、______ 、______ 、____…...
Redis为什么快?
目录 Redis为什么快?渐进式ReHash全局哈希表渐进式ReHash 缓存时间戳 Redis为什么快? 纯内存访问; 单线程避免上下文切换; 渐进式ReHash、缓存时间戳; 前面两个都比较好理解,下面我们主要来说下 渐进式…...
Zabbix从入门到精通以及案例实操系列
1、Zabbix入门 1.1、Zabbix概述 Zabbix是一款能够监控各种网络参数以及服务器健康性和完整性的软件。Zabbix使用灵活的通知机制,允许用户为几乎任何事件配置基于邮件的告警。这样可以快速反馈服务器的问题。基于已存储的数据,Zabbix提供了出色的报告和…...
水声声波频率如何划分?水声功率放大器可将频率放大到20MHz吗?
水声声波频率如何划分?水声功率放大器可将频率放大到20MHz吗? 现如今我们可以在地球任意地区实现通信,是因为电磁波的作用。但是我们都知道海洋占了全球十分之七面积,电磁波在水下衰减速度太快,无法做到远距离传输&am…...
网络攻防技术--论文阅读--《基于自动数据分割和注意力LSTM-CNN的准周期时间序列异常检测》
英文题目:Anomaly Detection in Quasi-Periodic Time Series based on Automatic Data Segmentation and Attentional LSTM-CNN 论文地址:Anomaly Detection in Quasi-Periodic Time Series Based on Automatic Data Segmentation and Attentional LST…...
C++ 学习 ::【基础篇:08】:C++ 中 struct 结构体的认识【面试考点:C 与 C++ 中结构体的区别】
本系列 C 相关文章 仅为笔者学习笔记记录,用自己的理解记录学习!C 学习系列将分为三个阶段:基础篇、STL 篇、高阶数据结构与算法篇,相关重点内容如下: 基础篇:类与对象(涉及C的三大特性等&#…...
Electron开发:打包和发布 Electron 应用
https://start.spring.io/ 在线数据分析网站 https://tj.aldwx.com/ https://www.spsspro.com/ win10如何分屏 拖到边缘 Electron 环境搭建 https://www.electronjs.org/zh/docs/latest/tutorial/%E6%89%93%E5%8C%85%E6%95%99%E7%A8%8B electron 隐藏菜单 electron 标题栏 设…...
【每日一题Day222】LC1110删点成林 | dfs后序
删点成林【LC1110】 给出二叉树的根节点 root,树上每个节点都有一个不同的值。 如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。 返回森林中的每棵树。你可以按…...
[ChatGPT] 从 GPT-3.5 到 GPT-5 的进化之路 | ChatGPT和程序员 : 协作 or 取代
⭐作者介绍:大二本科网络工程专业在读,持续学习Java,努力输出优质文章 ⭐作者主页:逐梦苍穹 ⭐如果觉得文章写的不错,欢迎点个关注一键三连😉有写的不好的地方也欢迎指正,一同进步😁…...
6.4 GDP调试多进程程序
目录 GDB调试多进程程序 安装gdb gdb编译 运行gdb 单步运行 从头到尾运行 下一步 运行子进程 同时运行父进程 查看运行的进程 切换进程 退出 GDB调试多进程程序 set follow-fork-mode child 设置GDB调试子进程 set follow-fork-mode parent 设置GDB调试父进…...
TDengine 时序数据的保留策略
“TDengine除vnode分片之外,还对时序数据按照时间段进行分区。每个数据文件只包含一个时间段的时序数据,时间段的长度由DB的配置参数days决定。这种按时间段分区的方法还便于高效实现数据的保留策略,只要数据文件超过规定的天数(系…...
Java-多线程解析1
一、线程的描述: 1、线程是一个应用程序进程中不同的执行路径比例如:一个WEB服务器,能够为多个用户同时提供请求服务;而 -> 进程是操作系统中正在执行的不同的应用程序,比如:我们可以同时打开系统的word和游戏 2、多…...
PHP 判断用户当前坐标是否在电子围栏内
可以使用射线法判断用户当前坐标点是否在电子围栏内。 具体步骤如下: 1. 将电子围栏的四个角坐标按顺序连接成一个封闭多边形。 2. 从用户当前坐标点向外发射一条射线,判断这条射线与多边形的交点个数。 3. 如果交点个数为奇数,则用户当前…...
Java版本工程管理系统源码企业工程项目管理系统简介
一、立项管理 1、招标立项申请 功能点:招标类项目立项申请入口,用户可以保存为草稿,提交。 2、非招标立项申请 功能点:非招标立项申请入口、用户可以保存为草稿、提交。 3、采购立项列表 功能点:对草稿进行编辑&#x…...
高速缓存(cache)的原理: 了解计算机架构与性能优化
计基之存储器层次结构 Author: Once Day Date: 2023年5月9日 长路漫漫,而今才刚刚启程! 本内容收集整理于《深入理解计算机系统》一书。 参看文档: 捋一捋Cache - 知乎 (zhihu.com)iCache和dCache一致性 - 知乎 (zhihu.com)C…...
【Vue3+TS项目】硅谷甄选day04--顶部组件搭建+面包屑+路由鉴权
顶部组件搭建 顶部左侧折叠和面包屑实现 左侧菜单刷新折叠的问题解决---属性default-active 折叠之后图标不见:icon放在插槽外面----element的menu属性:collapse project\src\layout\index.vue // 获取路由对象 import { useRoute } from vue-route…...
某oa 11.10 未授权任意文件上传
漏洞简介 之前也对通达 oa 做过比较具体的分析和漏洞挖掘,前几天看到通达 oa 11.10 存在未授权任意文件上传漏洞,于是也打算对此进行复现和分析。 环境搭建 https://www.tongda2000.com/download/p2019.php 下载地址 :https://cdndown.tongda…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...


