【类和对象】(上)

news2024/11/19 8:44:58

系列文章目录


文章目录

  • 系列文章目录
  • 👑 前言
  • 👑 一、什么是类,什么是对象
  • 👑 二、类的引入
  • 👑 三、类的定义
      • 👑三、1.类的两种定义方式:
  • 👑 四、类的内存计算
  • 👑五、this指针
    • 👑五、1.this指针的特性
  • 总结


👑 前言

本文从0开始详解什么是类,什么是对象等问题。
先讲讲什么是面向对象和面向面向过程编程。

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

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

举一个简单例子:在日常洗衣服中,面向过程的思想是:每一步都精分细作,逐步解决问题。
在这里插入图片描述
面向对象的思想是:洗衣服这件事情可以分成几个对象,人,洗衣机,洗衣粉,衣服。
整个过程主要是人,洗衣机,衣服,洗衣粉几个对象之间交互完成的。人不需要关心具体的细节如何操作。
在这里插入图片描述


👑 一、什么是类,什么是对象

简单来说,类就是一群相同或者相似的东西组成的群体。比如人类,鸟类,水果类等等。

对象就是一个具体的东西,比如,人,洗衣机,电脑等。
每个对象一定是有属于的那一类,比如人,属于人类,电脑属于电子产品类等。


👑 二、类的引入

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。比如:
之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量;现在以C++方式实现,会发现结构体中也可以定义函数。


👑 三、类的定义

C++中使用class来定义类

class className
{
   // 类体:由成员函数和成员变量组成
};

class是类的关键字, className是类名。

👑三、1.类的两种定义方式:

  1. 声明和定义全部放在类体中

注意:1.成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
2.在类内部定义成员函数,可能编译器会当成内联函数处理

2.声明和定义分离。

一般推荐使用第二种方法。
注意:使用该方法在定义前需要加上域作用限定符符号。
即成员函数名前需要加类名::
比如:

Tree.h
lass TreeNode
{
public:
	//函数成员
	void TreePrve(TreeNode& root);


private:
	//私有成员
};

Tree.cpp
void TreeNode::TreePrve(TreeNode& root)
{
	//
	// ...
	//
}

在Tree.cpp文件中定义函数前需要加上一个类名::


👑 四、类的内存计算

先看下面的案例:

class A1 
{
public:
	void f1() {}
private:
	int _a;
};

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

class A3 {};

int main()
{
	printf("%d\n", sizeof(A1));
	printf("%d\n", sizeof(A2));
	printf("%d\n", sizeof(A3));

	return 0;
}

输出结果为: 4 1 1

A1中包含一个int类型的成员变量和一个成员函数
A2中只包含个成员函数
A3既没有成员变量也没有成员函数

原因:没有成员变量的类的大小为1byte,这1个byte是用来占位的,表示该对象存在,不存储有效数据。

也就是说:类的成员函数是在公共代码段中存储的。

有成员变量的类依据结构体内存的对齐规则来存储。(不知道什么是结构体内存对齐的小伙伴可以搜一下)

结论:1.类的内存大小是成员变量的大小,不包含成员函数的大小。
2.没有成员变量的类的大小是1byte,这1个byte是用来占位的,表示该对象存在,不存储有效数据。

👑五、this指针

先看下面的代码:

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

void Print()
{
	cout <<_year<< "-" <<_month << "-"<< _day <<endl;
}

private:
	int _year;   // 年
	int _month;   // 月
	int _day;    // 日
};

int main()
{
	Date d1, d2;
	d1.Init(2023, 5, 4);
	d2.Init(2023, 5, 5);

	d1.Print();
	d2.Print();
	return 0;
}

在这段代码中,定义了一个日期类,日期类的两个成员函数的功能分别是初始化和打印成员变量。
在main函数中创建两个日期对象d1 和 d2;
d1对象初始化成2023,5,4,
d2初始化成2023,5,5

上面讲过,同一个类的成员函数是存在公共代码段的,每个对象的成员函数都是相同的。
那么为什么调用同一个函数,打印的结果却不相同?

主要原因在于一个隐含的this指针。
实际上在形参部分的传递是这样的:

p2
void Print(Date*this)
{
	cout <<this->_year<< "-" <<this->_month << "-"<<this->_day <<endl;
}
d1.Print(&d1)

d2也是如此。

注意:this指针不能在形参和实参部分显示传递。
也就是说,不能像p2这段代码一样写。
因为编译器已经帮我们做好了这样的工作,再次传形参和传this指针会重复。

注意:在类中的成员变量只是一个声明,不能通过下面的方式对类进行访问:

1.Date::_year
2.d1::_year

第一个写法的错误:类的成员变量只是一个声明,不能通过类名::,找到具体的成员变量。就像是建造房子,不能通过图纸找到具体的建的楼的位置在哪。
第二个写法错误:::是域作用限定符,d1是一个类实例化的对象,不是域。

👑五、1.this指针的特性

1.this指针存储在栈区空间中。
因为this是形参,this指针与其他形参一样存储在函数调用的栈桢里面。
在这里插入图片描述
在vs下,对this指针的传递进行了优化,对象的地址是放在ecx寄存器中,也就是this的值存储在ecx中。(这种优化方式取决于不同的编译器,不是绝对的)

2.this指针可以为空,但不能对this解引用
看下面的两道题:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}
private:
	int _a;
};

int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

// 2.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
  void PrintA()
 {
    cout<<_a<<endl;
 }
private:
	int _a;
};

int main()
{
  A* p = nullptr;
  p->PrintA();
  return 0;
}

解析:第一道题,p作为实参传递给this指针,this是空指针,但是在没有对空指针进行解引用,因为Print函数的地址不在对象中,而是在公共代码段,在编译期间就找到了Print函数的地址。

第二道题,p作为实参传递给this指针,this是空指针,调用Print函数没有对空指针进行解引用,因为Print的地址不在对象中,但是在Print内部,却调用了this指针,访问了_a.
本质是对空指针进行解引用。

3.this指针不能在形参和实参显示传递,但是可以在函数内部使用。


总结

以上是类和对象(上)的主要内容,本文讲述了:
1.面向对象和面向过程的区别和联系
2.什么是类,类对象
3.类的定义,使用
4.this指针等等


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

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

相关文章

Flutter学习之旅 - 页面布局Padding、Column、Flex、Expanded

文章目录 Padding线性布局组件(Column和Row)水平布局组件(Row)垂直布局组件(Column) 弹性布局(Flex&Expanded)ExpandedFlex 达到父元素的尺寸 Padding class MyHomePage extends StatelessWidget {const MyHomePage({Key? key}) : super(key: key);overrideWidget build(…

ATA-2000系列高压放大器介绍

ATA-2000系列是一款理想的可放大交、直流信号的高压放大器。最大差分输出1600Vp-p(800Vp)高压&#xff0c;可以驱动高压型负载。电压增益数控可调&#xff0c;一键保存常用设置&#xff0c;为您提供了方便简洁的操作选择&#xff0c;同时双通道高压放大器输出还可同步调节&…

FastJson序列化导致的 “$ref“

前言&#xff1a; 刚转后端没多久&#xff0c;在通过RPC调用其他组的服务的时候&#xff0c;其他组对接的同学说&#xff0c;你的入参是有问题的&#xff0c;然后他把入参发我&#xff0c;类似于下面的 json&#xff1a; {"addressMO": {"roomNumber": &…

795. 前缀和(C++和Python3)——2023.5.5打卡

文章目录 QuestionIdeasCode Question 输入一个长度为 n 的整数序列。 接下来再输入 m 个询问&#xff0c;每个询问输入一对 l,r 。 对于每个询问&#xff0c;输出原序列中从第 l 个数到第 r 个数的和。 输入格式 第一行包含两个整数 n 和 m 。 第二行包含 n 个整数&#…

哪种类型蓝牙耳机佩戴最舒服?公认佩戴舒适度高的蓝牙耳机

随着都市人生活水准的提高&#xff0c;人们开始享受起生活&#xff0c;观察身边的事物&#xff0c;佩戴蓝牙耳机能够满足自身基本通勤需求&#xff0c;现阶段不少蓝牙耳机质量越来越好&#xff0c;并且在功能、体验、技术上都具有相当的优势&#xff0c;性价比极高&#xff0c;…

Window下的反弹shell

什么是正向shell? 正向shell&#xff1a;控制端主动发起连接请求去连接被控制端&#xff0c;中间网络链路不存在阻碍。 反向shell&#xff1a;被控制端主动发起连接去请求连接控制&#xff0c;通常被控端由于防火墙受限制、权限不足、端口被占用等问题导致被控端不能正常接收…

短视频矩阵管理营销系统.源代码

一、短视频矩阵系统一般拥有以下几个主要功能&#xff1a; 1. 视频拍摄和剪辑功能&#xff0c;让用户轻松制作和发布短视频内容。 2. 视频分发和推广功能&#xff0c;矩阵管理发布、将制作好的短视频内容推送到各大短视频平台&#xff0c;实现效果最大化。 3. 数据监测和分析…

计算机三级嵌入式系统开发 知识点笔记

目录为搜索词&#xff0c;详情看每一节后图片 思维导图已上传&#xff0c;点击这里下载 嵌入式系统开发 全部章节图片第一章 嵌入式系统概论1.1SoCIP核 1.21.2.1ASCIIGB2312GB18030UTF8UTF16超文本字符形状两种描述方法 1.2.2数字图像 1.2.3音频 1.3传输介质分为 有线通信 和 无…

Windows下安装MySQL数据库+Navicat (从完全卸载到安装使用图文详细步骤,附安装包)

目录 第一章&#xff1a;如何完全卸载干净mysql教程&#xff08;三个步骤完全卸载&#xff09;1&#xff09;步骤一&#xff1a;卸载程序2&#xff09;步骤二&#xff1a;删除文件3&#xff09;步骤三&#xff1a;删除注册表信息 第二章&#xff1a;下载软件两种方式1&#xff…

架构师日记-深入理解软件设计模式 | 京东云技术团队

作者&#xff1a;京东零售 刘慧卿 一 设计模式与编程语言 1.1 什么是设计模式 设计模式&#xff08;Design pattern&#xff09; &#xff1a;由软件开发人员在软件开发中面临常见问题的解决方案&#xff0c;是经过长时间的试验积累总结出来的&#xff0c;它使设计更加灵活和…

MyBatis详细笔记

核心知识点 核心配置文件 映射文件概述 Dao层实现与代理开发实现 自动映射与自定义映射 参数传递与返回值 动态SQL 注解开发 缓存机制 总结 核心配置文件【mybatis-config.xml】 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 位置&#xff1a;resourc…

前端配置化表单组件设计方法 | 京东云技术团队

一、背景 前端开发中涉及表单的页面非常多&#xff0c;看似功能简单&#xff0c;开发快速&#xff0c;实则占去了很大一部分时间。当某个表单包含元素过多时还会导致html代码过多&#xff0c;vue文件过大。从而不容易查找、修改和维护。为了提高开发效率及降低维护成本&#x…

基于max30102的物联网病房监测系统(中断处理和主题逻辑)

目录 五、中断处理 六、主体框架 对采集数据的初始化 核心功能的实现 烟雾 通信帧格式 wifi接收数据的处理 OLED显示 五、中断处理 void SysTick_Handler(void) {TimingDelay_Decrement(); }void ESP8266_USART_INT_FUN(void) {uint8_t ucCh;if ( USART_GetITStatus (…

platform总线五级匹配解析

代码来源&#xff1a;开源linux内核linux-6.2.9 platform总线设备与驱动的匹配 对于device和driver无论哪个创建都会尝试主动寻找对方进行绑定&#xff0c;而platform bus总线的匹配原则如上面的代码所示&#xff0c;共有五级匹配&#xff0c;这里进行详细解析下&#xff1a; …

WRF模式

随着生态文明建设和“碳中和”战略的持续推进&#xff0c;我国及全球气候变化及应对是政府、科学界及商业界关注的焦点。气候是多个领域&#xff08;生态、水资源、风资源及碳中和等问题&#xff09;的主要驱动因素&#xff0c;合理认知气候变化有利于解释生态环境变化机理及过…

Android应用层开发学习 Framework 是必须的吗?

作为一名应用层 App 开发工程师&#xff0c;我们为什么要学习 Android Framework&#xff1f;答案很简单&#xff0c;为了不被淘汰&#xff01;在 2023 年的当下,不会点 Binder WMS AMS PMS 好像都找不到工作了&#xff0c;更过分的是应聘企业甚至希望你会点 RN Fluter 等跨平台…

元宇宙的重要底层技术

在元宇宙中&#xff0c;人们可以通过数字分身、化身&#xff08;可理解为虚拟化身&#xff09;、社交媒体化身和智能代理进行交互&#xff0c;这背后都需要底层技术支持。元宇宙的底层技术主要包括&#xff1a; VR/AR、5G/6G、区块链和人工智能。 VR/AR是元宇宙的主要交互设备…

JAVA新提案:努力简化Hello World写法

OpenJDK 的 JEP 445 提案正在努力简化 Java 的入门难度。这个提案主要是引入 “灵活的 Main 方法和匿名 Main 类” &#xff0c;希望 Java 的学习过程能更平滑&#xff0c;让学生和初学者能更好地接受 Java 。 提案的作者 Ron Pressler 解释&#xff1a;现在的 Java 语言非常适…

ES6-迭代器和生成器

一、迭代器概念 遍历器&#xff08; Iterator &#xff09;就是一种机制。它是一种接口&#xff0c;为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator 接口&#xff0c;就可以完成遍历操作。 1) ES6 创造了一种新的遍历命令 for...of 循环&#…

虹科方案 | 助力高性能视频存储解决方案-2

上篇文章《虹科方案 | 助力高性能视频存储解决方案-1》我们分享了虹科&ATTO 和 Avid 共同创建协作解决方案&#xff0c;助力高性能视频存储&#xff0c;今天我们再深入介绍一下我们的案例详情。 一、行业挑战 从高端广播设施到小型独立工作室的媒体后期制作环境都需要允许多…