【C++】类和对象入门(从struct到class带你了解类和对象!)

news2024/11/16 19:06:08
  • 🌸博主主页:@釉色清风
  • 🌸文章专栏:@C++
  • 🌸今日语录:人生本就是一首代写的诗歌,而他们的文字浅薄,不该被潦草地印刷着。所以在我笔下,“一重山有一重山地错落,我有我的平仄”。

类和对象

  • 🌼面向过程和面向对象的初步认识
  • 🌼类的引入
  • 🌼用class定义类
    • 🌻类的作用域
  • 🌼类声明与定义的分离
  • 🌼类中成员数据的规范化定义
  • 🌼类的实例化
  • 🌼类对象模型
    • 🌻计算类对象的大小
    • 🌻类对象的存储方式

🌼面向过程和面向对象的初步认识

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
比如说洗衣服,C语言更加注重过程。

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

对于C++引入面向对象是很有必要的。这是因为在一些大型的项目中,如果只是注重过程,那么就需要考虑很多很多的情况,不是仅仅就能够用if…else就能解决的。而如果在面向过程的设计中,中间某一过程的设计有一点问题,那么就将会导致整个项目出现问题。
而对于C++的面向对象,这里的面向对象不仅仅是只看重对象的,只是更加关注对象本身,它的属性以及它能做什么。在程序或者项目的设计过程中,往往是面向对象与面向过程相结合,各有用途,互相补充。
所以在C++的学习中,类和对象的思想是极为重要的。(一定要认真学习奥!)

🌼类的引入

首先,在学习C++的类之前,我们先以我们C语言中熟悉的结构体来进行引入。
先来看我们熟悉的栈结构:(如果忘了,可以简单看一下,只是引入,没看懂也没关系的可以直接跳过。)

typedef int datatype;
typedef struct Stack
{
    datatype *a;
    int top;
    int capacity;
}Stack;

对于指针a,理解:

接下来就是栈的基本操作:
栈的置空初始化—StackInit()

void StackInit(Stack *ps)
{
    assert(ps);//断言
    ps->a=NULL;
    ps->top=0;
    ps->capacity=0;
}

栈的初始化2.0—给栈开辟一点空间StackInit1()

void StackInit1(Stack *ps)
{
    assert(ps);
    ps->a=(datatype *)malloc(sizeof(Stack)*4);//开辟4个空间
    ps->capacity=4;
}

栈的销毁—StackDestory()

void StackDestory(Stack* ps)
{
    assert(ps);
    free(ps->a);
    ps->a=NULL;
    ps->top=ps->capacity=0;
}

入栈----StackPush()

void StackPush(Stack *ps,datatype x)
{
    assert(ps);
    //判断栈的空间是否已满
    if(ps->top==ps->capacity)
    {
         //扩容为原容量的2倍
        datatype *tmp=(datatype *)relloc(ps->a,sizeof(Stack)*capacity*2);
        ps->capacity=ps->capacity*2;
    }
    ps->a[ps->top]=x;
    ps->top++;
}

出栈----StackPop()

void StackPop(Stack *ps)
{
    assert(ps);
    //判断当前栈是否为空,若空则无法出栈,退出程序
    assert(ps->top >0);
    
    ps->top--;
}


当然这里还有一些函数…

通过上面我们简单定义的栈结构,在结构体内我们定义的是数据,在结构体外我们定义的是函数
所以说,在C语言中数据和方法是分离的。

因为C++兼容C语言,并对C语言中的一些用法进行了升级。那么在C++中,我们是可以直接照搬C语言中对结构体的定义的。

C++对C语言的struct进行了升级,升级成为了类。
其特点之一,就是类型就是类名,不需要加struct。
在C语言中,如果我们没有typedef一个结构体的话,那么我们需要这样定义一个结构体变量:

这样的定义有点冗杂,在C++中我们可以直接Stack s这样来定义。

其特点之二,类里面可以定义函数。
在上面的C语言的对于栈结构的定义,我们可以写成:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int datatype;
struct Stack
{
	datatype* a;
	int top;
	int capacity;
	//栈的置空
	void StackInit(Stack* ps)
	{
		assert(ps);
		ps->a = NULL;
		ps->top = 0;
		ps->capacity = 0;
	}
	//栈的初始化
	void StackInit1(Stack* ps)
	{
		assert(ps);
		ps->a = (datatype*)malloc(sizeof(Stack) * 4);//开辟4个空间
		ps->capacity = 4;
	}
	//栈的销毁
	void StackDestory(Stack* ps)
	{
		assert(ps);
		free(ps->a);
		ps->a = NULL;
		ps->top = ps->capacity = 0;
	}
	//入栈
	void StackPush(Stack* ps, datatype x)
	{
		assert(ps);
		//判断栈的空间是否已满
		if (ps->top == ps->capacity)
		{
			//扩容为原容量的2倍
			datatype* tmp = (datatype*)realloc(ps->a, sizeof(Stack) * capacity * 2);
			ps->capacity = ps->capacity * 2;
		}
		ps->a[ps->top] = x;
		ps->top++;
	}
	//出栈
	void StackPop(Stack* ps)
	{
		assert(ps);
		//判断当前栈是否为空,若空则无法出栈,退出程序
		assert(ps->top > 0);
		ps->top--;
	}
};

除此之外,因为一个结构体/类就是一个域,所以,我们还可以进一步简化函数的名字
如下图:

🌼用class定义类

上面结构体的定义,在C++中更喜欢用 class 来代替。
其实就是,将关键字struct改为关键字class,但仍然是由一些区别的。区别在于访问限定符。

在初学C++时,我们可以先暂且认为protected(保护)和private(私有)是没有区别的。
对访问限定符的简单说明:

  • ①public修饰的成员在类外可以直接被访问
  • ②protected和private修饰的成员在内外不能被直接访问。
  • ③访问权限,作用域重构该访问限定符出现的位置开始到下一个访问限定符出现为止。
  • ④如果后面没有访问限定符,作用域就到}即类结束。
  • class的默认访问权限是private,struct为public

所以说,在上面我们的栈结构的定义中,用struct定义类和用class定义类是不同的。如果我们不些访问限定符,struct默认里面的数据和方法是共有(public)的,在主函数中可以直接被访问。而class默认里面的数据和方法是私有(private)的,在主函数中不可以直接被访问。

🌻类的作用域

类定义一个新的作用域,类的所有成员都在作用域中,面我们来看一下访问限定符的使用:

🌼类声明与定义的分离

我们将类的声明写在.h头文件中,将类中的成员函数定义写在.cpp文件中。这和之前的写法是一样的。唯一需要我们注意的是,关于成员函数的定义,我们需要使用域作用限定符,告诉编译系统这个函数是属于哪个类的。

在头文件Stack.h中作声明:

在Stack.cpp文件中:

🌼类中成员数据的规范化定义

下面,我们来探讨一下类中成员数据的规范化定义。这一次,我们声明一个日期Date类,数据成员包含年(year)、月(month)、日(day)。然后 我们在定义一个成员函数 对日期进行初始化,参数仍然是年(year)月(month)日(day)。

这里我们需要着重看一下 初始化函数:在函数内部进行赋值的时候,year是参数year还是成员数据year?
答案是这里都是函数的参数year、month、day。这是因为,编译系统首先会在当前域里面检查,如果有,那就是使用当前域里面的这个变量,如果没有,才会去出当前域进行进一步查找。
很显然,函数的参数就是year、month、day就是当前域里面的。所以赋值操作中都是函数的参数,最终改变的也是函数参数的值而已。随着函数调用的结束,函数的栈帧销毁,这一番赋值操作并没有改变类中数据成员的值,所以我们进行打印,结果就是随机数了。


这时,有的同学,可能会说,那我们之间改变函数的参数不就可以了吗?
简化为这样:

void Init(int year,int month,int day);

但是在一个大项目中,这样做并不好,并不能反映参数的直接含义。
所以,更规范的写法就是 改变成员数据的定义:

private:
    int _year;
    int _month;
    int _day;

这是一种惯例,在成员数据变量前加"_"通常表示内部的。
所以,我们对上述我们的程序进行修改:

#include <iostream>
using namespace std;
class Date
{
public:
	void Init(int year, int month, int day);
	void display();
private:
	int _year;
	int _month;
	int _day;
};
void Date::Init(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
void Date::display()
{
	cout << _year << ":" << _month << ":" << _day;
}
int main()
{
	Date d;
	d.Init(2024, 3, 25);
	d.display();
	return 0;
}

🌼类的实例化


对象的定义也叫做类的实例化。
怎样理解类和对象?

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

🌼类对象模型

🌻计算类对象的大小

我们仍以上面的日期类为例,创建一个对象,计算对象的大小

得到对象d的大小为12个字节。

🌻类对象的存储方式

进而,我们对类对象的存储方式进行猜测。

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


根据,我们上述的日期类的运行结果,我们可以得知对象存储是按照第三种方式进行存储的,即只保存成员变量,成员函数存放在公共的代码段
接下来,我们再随意写两个类,对其进行进一步探索。

#include <iostream>
using namespace std;
class A
{
public:
	int a;
	int b;
private:
	void fun()
	{

	};
};
class B
{
public:
	void fun()
	{

	};
private:
	int a;
	char b;
};
int main()
{
	A a;
	B b;
	cout << endl << sizeof(a) << endl;
	cout << endl << sizeof(b) << endl;
	return 0;
}


由此,我们可以得出结论,①一个类的大小,实际就是该类中”成员变量”之和,这里的成员变量无关是public还是private的
②其次,我们还应当注意内存对齐问题。
内存对齐的规则如下:

③空类的大小为一个字节·。
无成员变量的类,其对象开一个字节,这个字节不存储有效数据,用来标识定义的对象存在过。

class C
{

};
int main()
{
	A a;
	B b;
	C c;

	cout << endl << sizeof(a) << endl;
	cout << endl << sizeof(b) << endl;
	cout << endl << sizeof(c) << endl;
	return 0;
}

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

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

相关文章

28位驻华大使、公使参访苏州金龙 点赞刚刚全球发布的新V系大巴

3月26日下午&#xff0c;由外交部组织的“驻华使节团参访江苏”活动走进苏州金龙。来自28个国家和国际组织的驻华大使、公使参观了苏州金龙展厅&#xff0c;并试乘体验了苏州金龙全新V系大巴。外交部中国政府欧洲事务特别代表吴红波&#xff0c;外交部礼宾司、翻译司、非洲司、…

javascript基础代码练习

一、输入新增病例数&#xff0c;累计确诊病例数&#xff0c;14天内聚集性疫情发生天数。新增或者累计确诊病例为0则该地区为低风险地区。新增大于0且累计确诊&#xff1c;50或者累计大于50且14天内聚集性疫情发生天数为0的地区为中风险地区。其他情况为高风险地区。 <!DOCT…

大数据Hadoop入门04 ——【HDFS shell操作】

一、HDSF shell命令行解释说明 1、介绍 命令行界面&#xff08;英语: command-line interface&#xff0c;缩写: CLl)&#xff0c;是指用户通过键盘输入指令&#xff0c;计算机接收到指令后&#xff0c;予以执行一种人际交互方式。Hadoop提供了文件系统的shell命令行客户端:…

labelme自动标注工具的安装和python代码修改

labelme嵌入SAM和EfficientSAM自动标注模型 目录: 1.labelme windows环境下安装python版本labelme 2.labelme.exe直接安装 3.labelme生成exe 4.labelme python代码修改 labelme自动标注使用方法 编辑/Create AI-Polygon 自动分割,直接生成分割图,标注为point,完成标注后…

Typora 主题配置

title: Typora主题配置 search: 2024-03-19 tags: “#Typora主题” Typora 主题配置 文章目录 Typora 主题配置Step-1 进入官方主题网站Step-2 选中主题&#xff0c;并点击DownloadStep-3 跳转到 github 网站Step-4 直接下载源码Step-5 解压下载的源码Step-6 找到下载源码中的…

01背包-动态规划

01背包 易知状态转移方程为&#xff1a; dp[i][j] max(dp[i-1][j],dp[i-1][j-v[i]]w[i]) 代码 N,V map(int,input().split()) v, w [0],[0] # 体积v&#xff0c;价值w for i in range(N):a list(map(int,input().split()))v.append(a[0]) # 体积viw.append(a[1]) # 价值w…

NO11 蓝桥杯单片机之DS18B20数字温度计

DS18B20数字温度计这个模块和以往单片机学习的模块可能不同&#xff0c;这里还要知道其头文件&#xff08;.h&#xff09;和.c文件代码的理解。 具体这个温度计是怎么实现检测温度的&#xff0c;呃呃呃呃呃这可能就要去查阅专业资料&#xff0c;涉及的知识体系应该很庞大&…

公众号软文怎么写?媒介盒子告诉你

公众号软文是指在微信公众号平台上发布的一种营销文章&#xff0c;旨在通过有针对性的内容和亲民易懂的语言吸引读者&#xff0c;提高品牌知名度和销售额。然而公众号软文想要写好需要一定的技巧&#xff0c;今天媒介盒子就来和大家聊聊。 一、 分析用户需求 文案是写给用户看…

【深度学习】图片预处理,分辨出模糊图片

ref:https://pyimagesearch.com/2015/09/07/blur-detection-with-opencv/ 论文 ref:https://www.cse.cuhk.edu.hk/leojia/all_final_papers/blur_detect_cvpr08.pdf 遇到模糊的图片&#xff0c;还要处理一下&#xff0c;把它挑出来&#xff0c;要么修复&#xff0c;要么弃用。否…

【数学】第十三届蓝桥杯省赛C++ A组/研究生组 Python A组/研究生组《数的拆分》(C++)

【题目描述】 给定 T 个正整数 &#xff0c;分别问每个 能否表示为 的形式&#xff0c;其中 , 为正整数&#xff0c;, 为大于等于 2 的正整数。 【输入格式】 输入第一行包含一个整数 T 表示询问次数。 接下来 T 行&#xff0c;每行包含一个正整数 。 【输出格式】 对于…

CentOS 7 下安装RabbitMQ教程

CentOS 7 下安装RabbitMQ教程 一、做准备&#xff08;VMWare 虚拟机上的 CentOS 7 镜像 上安装的&#xff09; &#xff08;1&#xff09;准备RabbitMQ的安装包&#xff08;rabbitmq-server-3.8.5-1.el7.noarch&#xff09;下载地址mq &#xff08;2&#xff09;还得准备erl…

你的 Python 代码需要解释一下了!

Python 是一种相对简单的编程语言。它主要以解释型语言著称&#xff0c;这意味着每行代码都要通过解释器逐行执行。不过在某些时候&#xff0c;将 Python 代码翻译成计算机可以理解的内容&#xff0c;然后再逐行执行&#xff0c;可以减少繁琐。 在这种情况下&#xff0c;编译器…

日本EPSON 爱普生HUD汽车抬头显示系统芯片

目前HUD产品在新车上的配装率逐年上升&#xff0c;预计在2025年将达到30%。那么在介绍爱普生HUD整合方案之前&#xff0c;让我们先了解一下什么叫HUD。 HUD&#xff08;Head Up Display&#xff09;中文叫抬头显示系统&#xff0c;又被叫做平行显示系统。早被应用在飞机辅助…

2024游泳耳机哪个牌子好?分析测评四大热门游泳耳机

随着科技的不断发展&#xff0c;游泳耳机已经成为游泳爱好者们在水中畅游时的最佳伴侣。近年来游泳耳机市场涌现出了众多品牌和产品&#xff0c;让人眼花缭乱。为了帮助大家挑选到最适合自己的游泳耳机&#xff0c;我们特意对市面上四大热门游泳耳机进行了详细的分析测评&#…

【正点原子FreeRTOS学习笔记】————(13)队列集

这里写目录标题 一、队列集简介&#xff08;了解&#xff09;二、队列集相关API函数介绍&#xff08;熟悉&#xff09;三、队列集操作实验&#xff08;掌握&#xff09; 一、队列集简介&#xff08;了解&#xff09; 一个队列只允许任务间传递的消息为同一种数据类型&#xff…

【字节二面】SpringBoot可以同时处理多少请求

目录 一、示例代码二、那么springboot可以处理多少请求&#xff1f;三、maxConnections、maxThreads、acceptCount的关系 一、示例代码 RestController Slf4j public class RequestController {GetMapping("/test")public String test(HttpServletRequest request) …

飞书很好,但赢不了,只能裁员

心碎飞书 3 月 26 日&#xff0c;字节跳动旗下产品飞书的 CEO 谢欣发布全员信&#xff0c;正式宣布进行新一轮的组织调整&#xff0c;即裁员。 内部全员信如下&#xff1a; 我有不少朋友是在字节跳动&#xff0c;甚至就在 Lark 的。 同时我也因为会经常和一些平台的运营小伙伴有…

抖店被判无货源违规后该怎么办?避免这几项!开抖音小店无风险!

哈喽~我是电商月月 今天我们来聊一聊抖音小店被提示无货源风险后 商家怎么做&#xff0c;才能最大化挽回损失&#xff0c;以及后续如何避免的解决方案&#xff1a; 一&#xff0e;被判无货源的四个程度 1.收到平台提示&#xff1a;店铺存在无货源风险时 这个时候店铺基本就…

设置http响应报文

一、总结&#xff1a; (1)设置响应状态码&#xff1a; response.statusCode (2)设置响应状态描述&#xff1a; response.statusMessage() 使用的极少 (3)设置响应头信息&#xff1a; response.setHeader(头值,头名) (4)设置响应体&#xff1a; response…

个人或企业防止网络攻击的方法总结

个人或企业防止网络攻击的方法总结。 随着威胁形势的不断发展&#xff0c;建立全面的网络安全解决方案需要外围安全性和主动的网内防御 。随着网络攻击的范围&#xff0c;规模和频率不断增加&#xff0c;网络卫生正变得越来越重要。 与个人卫生相似&#xff0c;网络卫生是指旨…