【C++】——类与对象引入和认识

                                                创作不易,多多支持!

前言

有了上一篇博客的基础以后,就正式进入C++类和对象的领域了,如果看完本篇文章对你有用,还请多多支持!!😘😘

一 面向过程和面向对象

1.面向过程

在之前用c语言的时候,我们写一个程序,通常需要把这个程序分成很多给步骤,所以c语言是一个关注过程,面向过程的语言。

很经典的例子就是我们洗衣服,得分为找到要洗的衣服,然后放进盆子里面,然后倒入洗衣液,再

之后放水,之后就是用手洗或者用洗衣机洗,洗完之后还需要晾衣服,假如是这样一个程序,那么

就是会分成很多个步骤逐个完成。

2.面向对象

C++是基于面向对象的,关注的是对象,它不太关注其中过程,只关心对象就行。

比如我们洗衣服就分为人,要洗的衣服,洗衣机,三个对象而已,我们不需要关注太多,那行繁琐

的步骤可能是在某个对象里面完成的,其他对象不需要关注它到底是怎么完成的

二  类的引入

 在C语言中我们学过结构体,C++的类就是对结构体的升级

因为在结构体中只能是定义变量,却不能定义函数,然而类是可以的

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
struct A
{
	void fun()//函数
	{
		cout << "类和对象" << endl;
	}
	
	int _year;
	int _momth;
	int _day;
};
int main()
{
	A a;
	a.fun();
	return 0;
}

如果是c语言则不能这样使用,但是对于C++来说,C++更喜欢用class来代替struct

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A
{
public:
	void fun()
	{
		cout << "类与对象" << endl;
	}
private:
	int _year;
	int _momth;
	int _day;
};
int main()
{
	A a;
	a.fun();
	return 0;
}

如果用class去修饰,那么这个类的内容称为类的成员,里面的函数称为类的方法或成员函数,里面的变量称为类的成员变量

 三  类的定义

类的定义有两种方式

第一种就是上面那种,全部放在类体中,这种放在类里面的函数,编译器会把他们当作内联函数

第二种是把函数的定义放在外面,也就是把声明凡在.h文件,把定义放在.cpp,如果是这样定义的话,那么我需要在函数定义的地方加上域访问符

 第一张图是.h文件的,第二张图是.cpp文件的

四  类的访问限定符及封装

4.1  访问限定符

这里的访问限定符其实正上面就已经有了介绍,就是外面用类把对象的属性和方法封装起来,通过访问权限选择性去给用户使用

这里就是public,private,protected,三种

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

 其实上面第五点提到了class与struct的区别,其实不然,他们的区别还有在继承和模板的位置有,这里就不一一介绍,在后面再说

4.2  封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来
和对象进行交互
C++ 语言中实现封装,可以 通过类将数据以及操作数据的方法进行有机结合,通过访问权限来
隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用

 五  类的实例化

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

我们写的类其实是对对象的描述,也就是相当于打了一个草稿,或者画了一张图纸,并没有去把它变成一个物体也就是没用开辟空间给它,只有当我们把它实例化也就是创建对象的时候,它才会对分配空间存储成员变量

这里的空间并没有分配给里面的函数,因为函数是不存储再对象里面的,是存储在公共的代码区里面,这一点尤为重要

所以有了上面的认识,我们在计算类的大小的时候就不能把里面的函数大小算进来,只算里面的成员变量就行

对于空类来说,其大小为1个字节,这1个字节没有意义,只是说明它存在而已

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

六  this指针

我先来看一段代码

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(2022,1,11);
   d2.Init(2022, 1, 12);
   d1.Print();
   d2.Print();
   return 0;
}

从代码中我们可以看出对象d1和d2都共用一个这个初始化函数,但是这个初始化函数是怎么分别出这两个对象不一样的呢?(类里面的函数都在代码区,只有成员变量算在类里面,占据类的内存) 

其实原本应该是这样的

class Date
{ 
public:
 void Init(Date*const this,int year, int month, int day)//这里就是把隐含的指针显示出来
 {
    this->_year = year;
    this->_month = month;
    this->_day = day;
 }
 void Print()
 {
    cout <<_year<< "-" <<_month << "-"<< _day <<endl;
 }
private:
    int _year;     // 年
    int _month;    // 月
    int _day;      // 日
};
int main()
{
   Date d1, d2;
   d1.Init(2022,1,11);
   d2.Init(2022, 1, 12);
   d1.Print();
   d2.Print();
   return 0;
}

所以说this指针的特性就是

1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
2. 只能在成员函数”的内部使用
3. this指针本质上是成员函数的形参,当对象调用成员函数时,将对象地址作为实参传递给
this形参。所以对象中不存储this指针。
4. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传
递,不需要用户传递

所以我们一般不会像第二个那样去写,一般是采用第一个的形式去写,这样比较方便一点 

七 C语言和C++实现栈的比较 

现在我们用C去实现一个栈

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
typedef int DataType;
typedef struct Stack
{
	DataType* a;
	int size;
	int capacity;
}Stack;
void StackInit(Stack* ps)
{
	assert(ps);
	Stack* tmp;
	tmp = (DataType*)malloc(sizeof(DataType)*4);
	if (tmp == NULL)
	{
		return 0;
	}
	else
	{
		ps->a = tmp;
	}
	ps->size = 0;
	ps->capacity = 4;
}
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}
void CheckCapacity(Stack* ps)
{
	assert(ps);
	if (ps->capacity == ps->size)
	{
		int newcapacity = ps->capacity * 2;
		DataType* tmp = (DataType*)realloc(ps->a, sizeof(DataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return 0;
		}
		else
		{
			ps->a = tmp;
			ps->capacity = newcapacity;
		}
	}
}
void StackPush(Stack* ps,DataType x)
{
	assert(ps);
	CheckCapacity(ps);
	ps->a[ps->size++] = x;
}
bool StackEmpty(Stack* ps)
{
	assert(ps);
	return 0 == ps->size;
}
void StackPop(Stack* ps)
{
	if (StackEmpty(ps))
		return;
	ps->size--;
}
DataType StackTop(Stack* ps)
{
	assert(!StackEmpty(ps));
	return ps->array[ps->size - 1];
}
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->size;
}

从里面可以看出来其实还是很麻烦的,注意这里我输入输出依然是c++的,因为c++兼容c,所以形式是c的,但是里面混了一点c++的东西

 那现在我们用C++ 去实现这个栈

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
typedef int DataType;
class Stack{
public:
	void StackInit()
	{
		Stack* tmp;
		tmp = (DataType*)malloc(sizeof(DataType) * 4);
		if (tmp == NULL)
		{
			return 0;
		}
		else
		{
			_a = tmp;
		}
		_size = 0;
		_capacity = 0;
	}
	void StackDestroy()
	{
		free(_a);
		_a = NULL;
		_size = 0;
		_capacity = 0;
	}
	void StackPush(DataType x)
	{
		CheckCapacity();
		_a[size++] = x;
	}
	bool StackEmpty()
	{
		return 0 == _size;
	}
	void StackPop()
	{
		if (StackEmpty())
			return;
		_size--;
	}
	DataType StackTop()
	{
		assert(!StackEmpty());
		return ps->array[_size - 1];
	}
	int StackSize()
	{
		return _size;
	}
private:
	void CheckCapacity()
	{
		
		if (_capacity == _size)
		{
			int newcapacity = _capacity * 2;
			DataType* tmp = (DataType*)realloc(ps->a, sizeof(DataType) * newcapacity);
			if (tmp == NULL)
			{
				perror("realloc fail");
				return 0;
			}
			else
			{
				_a = tmp;
				_capacity = newcapacity;
			}
		}
	}
	DataType* _a;
	int _size;
	int _capacity;
};

从两者的比较我们可以看出,如果我们用c++的方式去实现栈,那么就会减少大量的指针问题

C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在
类外可以被调用,即封装 ,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。
而且每个方法不需要传递Stack*的参数了 ,编译器编译之后该参数会自动还原,即 C++ Stack *
参数是编译器维护的, C 语言中需用用户自己维护

这里的指针都被this指针所替代,不是说没有指针,只是这个this指针是看不见的隐含指针而已

所以指针不需要我们去维护,但是在C中需要自己去维护,这样就比较麻烦而且比较容易出错

希望看到这里,可以给一波关注加收藏!! 😁😁

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DFS和回溯专题:组合总和

DFS和回溯专题&#xff1a;组合总和 题目链接: 39.组合总和 参考题解&#xff1a;代码随想录 题目描述 代码纯享版 class Solution {public List<List<Integer>> list_all new ArrayList();public List<Integer> list new ArrayList();public List<…

基于贝叶斯算法的机器学习在自动驾驶路径规划中的应用实例

目录 第一章 引言 第二章 数据准备 第三章 贝叶斯路径规划模型训练 第四章 路径规划预测 第五章 路径执行 第六章 实验结果分析 第一章 引言 自动驾驶技术的发展带来了自动驾驶车辆的出现&#xff0c;而路径规划作为自动驾驶车辆的关键功能之一&#xff0c;对于确定最佳行…

2024年Q1季度平板电视行业线上市场销售数据分析

Q1季度平板电视线上市场表现不如预期。 根据鲸参谋数据显示&#xff0c;2024年1月至3月线上电商平台&#xff08;京东天猫淘宝&#xff09;平板电视累计销量约360万件&#xff0c;环比下降12%&#xff0c;同比下降30%&#xff1b;累计销售额约99亿元&#xff0c;环比下降28%&a…

OSI网络七层协议<随手笔记>

1.OSI OSI&#xff08;Open System Interconnect&#xff09;&#xff0c;即开放式系统互连。 一般都叫OSI参考模型&#xff0c;是ISO组织在1985年研究的网络互连模型。该体系结构标准定义了网络互连的七层框架&#xff08;物理层、数据链路层、网络层、传输层、会话层、表示层…

Java工程maven中排包exclude的操作

一、背景 在开发项目时依赖了新的jar包&#xff0c;结果工程启动时报错了&#xff0c;此时应该是包依赖冲突的问题。 二、确定冲突的依赖包 执行mvn clean install&#xff0c;通过报错信息来确定冲突的jar包信息 三、排除冲突包的方案 有两种冲突的情况&#xff1a; 1&am…

电梯节能的推广意义

之前关于电梯能量回馈设备&#xff0c;小伍已经做了很多介绍&#xff0c;那么小伙伴们&#xff0c;他的推广意义你真的了解了么&#xff1f; 第一&#xff1a;节电降耗&#xff0c;电梯在运行过程中会产生大量的惯性能量&#xff0c;这些能量如果不被利用就会浪费。能量回馈技术…

【C语言】每日一题,快速提升(5)!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. strlen函数 2. strcpy函数 3. strcat函数 题目&#xff1a;模拟实现 strlen--strcpy--strcat--三个函数 1. strlen函数 字符串计算 #include <stdio.h…

[笔试训练](二)

004 牛牛的快递_牛客题霸_牛客网 (nowcoder.com) 题目&#xff1a; 题解&#xff1a; 使用向上取整函数ceil()&#xff0c;&#xff08;记得添加头文件#include<cmath>&#xff09; #include <iostream> #include <cmath> using namespace std;int main(…

TensorFlow文件读取 --TFRecords文件

TFRecords文件 是一种二进制文件&#xff0c;能够很好的利用内存&#xff0c;更方便复制和移动&#xff0c;并且不需要单独的标签文件 使用步骤 1&#xff09;获取数据 2&#xff09;将数据填入到Example协议内存块&#xff08;protocol buffer&#xff09; 3&#xff09;将协…

冯唐成事心法笔记

文章目录 卷首语 管理是一生的日常&#xff0c;成事是一生的修行PART 1 知己 用好自己的天赋如何管理自我用好你的天赋成大事无捷径如何平衡工作和生活做一个真猛人做自己熟悉的行业掌控情绪如何对待妒忌和贪婪如何战胜自己&#xff0c;战胜逆境真正的高手都有破局思维有时候…

利用动态规划在有向图上实现高效语音识别算法

在现代语音识别系统中&#xff0c;动态规划是一种非常关键的技术。它能够帮助我们将复杂的语音信号转换为可理解的文字信息。在本文中&#xff0c;我们将探讨如何使用动态规划方法在有向图上实现语音识别。我们将首先介绍问题的背景和基本概念&#xff0c;然后提供一个高效的算…

基于开源CrashRpt与微软开源Detours技术深度改造的异常捕获库分享

目录 1、异常捕获模块概述 2、为什么需要异常捕获模块&#xff1f; 3、在有些异常的场景下是没有生成dump文件的 4、开源异常捕获库CrashRpt介绍 5、对开源库CrashRpt的改进 C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持…

NX二次开发UF_VEC(向量运算)常用函数

目录 一、概述 二、函数的介绍 2.1 UF_VEC3_add&#xff08;两向量相加&#xff09; 2.2 UF_VEC3_affine_comb&#xff08;未缩放和缩放后的和&#xff09; 2.3 UF_VEC3_angle_between&#xff08;使用第三个向量确定连个向量的夹角&#xff09; 2.4 UF_VEC3_ask_perpendicu…

【状态机dp 动态规划】100290. 使矩阵满足条件的最少操作次数

本文涉及知识点 动态规划汇总 状态机dp LeetCode100290. 使矩阵满足条件的最少操作次数 给你一个大小为 m x n 的二维矩形 grid 。每次 操作 中&#xff0c;你可以将 任一 格子的值修改为 任意 非负整数。完成所有操作后&#xff0c;你需要确保每个格子 grid[i][j] 的值满足…

人人可拥有刘强东同款数字人分身!

每个人都可以拥有东哥同款数字人分身直播间进行直播带货&#xff0c;怎样克隆自己的数字人形象&#xff1f; 青否数字人克隆源码的克隆效果媲美真人&#xff1a; 仅需将真人录制的2-6分钟视频上传至克隆端后台&#xff0c;系统便会自动启动自动克隆。3-5小时后&#xff0c;即可…

LR系统关联错误

报错提示&#xff1a; 開日&#xff1a;Vuser艳湾辫触?mdrv.dat函欢?CCI聞/珞涓ECCIDebug剧涓?off&#xff1f;璀&#xff1a;十cciext.dll钙筑婧&#xff1f;ExtPerProcessInitialize踩整伴叔璇&#xff1f;-19797&#xff1a;缩跨v涓&#xff1f;璋幂椹下动清鳄"叶璐…

Oracle交换分区测试

1、用exchange分区表减少初始化过程中对业务中断的影响 2、创建分区表 create table t_p (id number,name varchar2(30),addr varchar2(50)) partition by range(id) (partition p1 values less than(10), partition p2 values less than(20), partition p3 values less …

免费听音乐,下载音乐mp3,mp4,歌词的网站分享(2024-04-22)

亲测&#xff01;&#xff01;&#xff01; 1、音乐客 免费听和免费下载 经典老歌 - 音乐客音乐客,yinyueke.net,免费音乐,免费在线音乐播放器,免费下载音乐,音乐&#xff0c;播放器&#xff0c;下载&#xff0c;播放&#xff0c;DJ&#xff0c;免费,mp3,高音质&#xff0c;…

A4云打印仅需5分/页?云打印多少钱?云打印怎么收费?

随着互联网技术的发展&#xff0c;越来越多的同学在打印资料的时候都开始转向线上&#xff0c;转向云打印服务了。云打印服务不仅可以给我们节省很多时间&#xff0c;价格方面较打印店也更有优势。那么云打印多少钱&#xff1f;云打印怎么收费&#xff1f;今天小易就带大家来了…

git 某个分支代码回滚到某次push的步骤

切换到需要操作的分支 git checkout 分支名称 命令&#xff1a; git log 获取代码的提交记录&#xff0c;按小写q退出当前命令对话。 获取某次提交或者合并的hash值&#xff1a;如&#xff1a;2cf0f19ab21aa62f5ebffa5f08caed3f63842346 使用reset命令对当前分支进行回退到某…