C++基础(2)——类和对象

目录

1. 类的引入:

2. 类的定义:

2.1类的定义以及基本结构:

2.2 类的访问限定符:

3. 类的声明与定义的分离:

4. 类的实例化:

5. 类的大小计算:


1. 类的引入:

      在数据结构系列的文章中,经常会使用结构体来构建例如顺序表,链表等数据结构的大体结构。在C语言中,结构体内部只能定义变量。但是在C++中,对结构体进行了修改,称之为类,类中不但可以定义变量,也可以定义函数。同时,类也兼容了C语言中结构体的所有用法。为了具体体现两种语言中结构体的不同,下面将通过一个示例进行解释:

     在数据结构的栈这一部分中,对于栈这一数据结构的定义可以由下面的代码表示:

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

void StackInit(struct Stack* ps);

void StackPush(struct Stack* ps, int x);

(注:此处只简单的引入栈的基本结构以及部分功能函数的声明,用于解释类和结构体的不同)

    在C语言中,如果不对结构体进行typedef来重命名,则在使用时,必须带上struct。在C++中,对这部分进行了优化,在使用结构体时,只需要结构体名即可。例如对于上述代码,在C语言中,如果想要使用结构体,需输入

struct Stack S1;

而在C++中使用时,类名即类型,不需要加上struct。即:

Stack S1;

      上面提到了,在C++中,类(结构体)中可以定义函数,如果将开头关于栈的相关代码利用C++进行修改,可以很好的简化代码书写,即:

struct Stack
{
	int* a;
	int top;
	int capacity;

	void Init();

	void Push(int x);
};

        从上面给出的代码不难看出,利用C++对栈的相关代码进行改写时,不但让函数中的参数数量减少,并且还化简了C语言中与栈相关的功能函数的函数名。例如向栈中插入元素,C语言中此函数的函数名为StackPush,在C++中为Push。这是因为在C语言中,由于结构体内部不能定义函数,并且对于其他种类的数据结构中,均有初始化函数Init。如果不在函数名之前加上不同种类数据结构的名字加以区分,并且在C语言中并不存在函数重载。会造成错误。

       而在C++中,因为类的作用域(对于类的作用域将在文章后部给予相关解释,本处只是提出这个概念关系,并且可以在类中定义函数,因此,可以在不同的类中,同时定义Init

2. 类的定义:

2.1类的定义以及基本结构:

      上面给出了定义类的一个方法,即利用struct,本部分给出另一个用于定义类的关键字class,具体结构如下:

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

       其中,class为定义类的关键字,ClassName为类的名字,{}{}中为类的主体,类主体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。

2.2 类的访问限定符:

  对于类的访问限定符,为public,protected,private

三者之间的区别为,public修饰的成员变量可以在类外访问。而protected,private修饰的成员变量只能在类中被访问。

对于三个访问限定符的作用权限,可分为下面两种情况:

    1.如果任意访问限定符(例如下面给出代码中访问限定符private)后面的代码中存在其他的访问限定符(例如下面代码中的public),则private的作用权限在遇到public后截止。例如:

class Stack
{
	private:
		int* a;
		int top;
		int capacity;

    public:
	void Init();

	void Push(int x);
};

     2.如果任意的访问限定符(例如下面代码中的public)中截止到类的"}"之前没有其他的访问限定符,则public的访问权限作用截止到类的末尾。例如:

class Stack
{
	private:
		int* a;
		int top;
		int capacity;

    public:
	void Init();

	void Push(int x);
};

  对于struct,class这两个关键字都可以来定义类。二者的不同主要体现在默认的访问权限上,对于struct,其默认的访问权限为public。对于class,其默认的访问权限为private

3. 类的声明与定义的分离:

     在之前数据结构的章节中,经常会让函数的声明和定义分离在两个文件中,对于类而言,加入在类中给出一个函数的声明,在外部给出函数的定义,方法如下:

void Stack::Init()
{
	a = 0;
	top = 0;
	capacity = 0;
}

  除了上述情况,如果将函数的声明与定义同时放在类中,会出现两种情况:

1. 函数的代码行数较少,此时函数会自动变为内联函数。

2. 函数的代码行数较多,函数不会变成内联函数。

class Stack
{
	private:
		int* a;
		int top;
		int capacity;

    public:
		void Init();

		void Push(int x)
		{
			a[top] = x;
			capacity++;
			top++;
	    }
};

       因此,对于较为短小的函数,适合之间定义在类中,而较为复杂的函数适合采用声明与定义分离的方法。

4. 类的实例化:

  定义如下:用类类型创建对象的过程,称为类的实例化。类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类,并没有分配实际的内存空间来存储它。例如:

class Stack
{
public:
	int _year;
	int _month;
	int _day;
};

        在类中给出上面三个变量,需要注意,类中的变量,只是变量的声明,这种变量并没有在内存中开辟空间,在没有进行类的实例化的情况下,并不能进行使用,例如:

int main()
{

	Stack::_day = 2023;

	return 0;
}

        如果运行上述给出的代码,编译器会显示报错。这是因为此时的变量day只是一个声明,并没有在内存中开辟空间。

      如果想要使用上述变量,首先需要进行一次类的实例化,代码如下:

int main()
{

	Stack Time; //实例化
	Time._day = 12;
	Time._month = 11;
	Time._year = 2023;

	return 0;
}

5. 类的大小计算:

例如对于下面给出的类:

class Stack1
{
	void Push(int x)
	{
		
	}

public:
	int _year;
	int _month;
	int _day;
};

class Stack2
{


public:
	int _year;
	int _month;
	int _day;
};

      不难发现,上述代码给出的两个类中,不同点为Stack1中包含了一个函数,Stack2中只声明了三个整型变量。通过下面的代码打印其大小:
 

int main()
{
	Stack1 time;
	Stack2 time1;

	cout << sizeof(time) << endl;
	cout << sizeof(time1) << endl;
	return 0;
}

结果如下:

       不难发现,二者大小的值是相同的,也就是说,计算类的大小时,并没有将类中的函数计算在内。这是因为,在每次调用时,类中的变量都会接收不同的值,而函数除了传递的形式参数没有任何变化,因此,在类中,变量是独立存储的,而函数,则是在一个公共空间中存储的。

       如果将上述的类进行部分更改,即:

class Stack3
{


public:
	char _year;
	int _month;
	int _day;
};

 此时打印结果为:

通过打印结果不难发现,类中变量的存储依旧满足内存对齐原则,即:

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

在类的大小这部分,还有一个特殊的例子,即空类:

class Stack4
{

};

当打印空类的大小时,即:
 

int main()
{
	Stack4 a;

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

结果如下:

因此,对于上述无成员变量的类的对象(a),大小为1字节。这1字节并不存储有效数字,仅用来表示定义的对象(a)存在。

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

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

相关文章

使用openvc进行人脸检测:Haar级联分类器

1 人脸检测介绍 1.1 什么是人脸检测 人脸检测的目标是确定图像或视频中是否存在人脸。如果存在多个面&#xff0c;则每个面都被一个边界框包围&#xff0c;因此我们知道这些面的位置 人脸检测算法的主要目标是准确有效地确定图像或视频中人脸的存在和位置。这些算法分析数据…

[Android]修改应用包名、名称、版本号、Icon以及环境判断和打包

1.修改包名 在Android Studio中更改项目的包名涉及几个步骤&#xff1a; 打开项目结构: 在Android Studio中&#xff0c;确保您处于Android视图模式&#xff08;在左侧面板顶部有一个下拉菜单可以选择&#xff09;。 重命名包名: 在项目视图中&#xff0c;找到您的包名&…

结构型设计模式07-享元模式

结构型设计模式07-享元模式 1、享元模式介绍 享元模式是一种结构型设计模式&#xff0c;旨在通过共享对象来减少内存使用和提高性能。它主要用于处理大量细粒度对象的情况&#xff0c;其中许多对象具有相似的属性和行为。 在享元模式中&#xff0c;对象分为两种类型&#xf…

互联网大厂招兵买马开发鸿蒙应用,移动开发的春天又来了?

日前&#xff0c;美团拟开发鸿蒙系统APP的多个相关岗位正招聘开发人员引发业内关注。事实上&#xff0c;鸿蒙开发者已经成为京东、WPS、凤凰新闻、微博等互联网大厂争相招聘的人才&#xff0c;且招聘岗位众多。也就是说&#xff0c;这些公司正在加快鸿蒙化开发&#xff0c;为鸿…

计算机毕业设计选题推荐-校园交流平台微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

录制GIF图,动态图

软件下载链接&#xff1a; https://www.cockos.com/licecap/ 参考链接&#xff1a; https://chat.xutongbao.top/

Linux学习第40天:Linux SPI 驱动实验(一):乾坤大挪移

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 主从工作方式完成数据交换&#xff0c;形象的说就是武侠中的乾坤大挪移。 本章实验的最终目的就是驱动 I.MX6UALPHA 开发板上的 ICM-20608 这个 SPI 接口的六轴传…

2023.11.13 hive数据仓库之分区表与分桶表操作,与复杂类型的运用

目录 0.hadoop hive的文档 1.一级分区表 2.一级分区表练习2 3.创建多级分区表 4.分区表操作 5.分桶表 6. 分桶表进行排序 7.分桶的原理 8.hive的复杂类型 9.array类型: 又叫数组类型,存储同类型的单数据的集合 10.struct类型: 又叫结构类型,可以存储不同类型单数据的集合…

【函数讲解】pygmo中的函数 fast_non_dominated_sorting() + 利用支配关系,学习一个SVM分类器,将解分为两类

这个函数是用来执行非支配排序的&#xff0c;可以分层构建Pareto&#xff0c;并返回每一层的解以及每个解支配其他解的索引、解被其他解支配的次数、解所在的非支配层级。这个函数对这些解进行非支配排序&#xff0c;并返回四个数组&#xff1a;ndf, dl, dc, 和 ndr。 ndf (Non…

CentOS7、CentOS8 如何修改ip信息(修改网络信息)(无图形界面)(亲测可用)

文章目录 CentOS 7方法一&#xff1a;使用 nmcli 命令方法二&#xff1a;编辑配置文件&#xff08;我的CentOS7是使用这种方法&#xff0c;亲测可用&#xff09; CentOS 8方法一&#xff1a;使用 nmcli 命令方法二&#xff1a;编辑配置文件 在 CentOS 系统中&#xff0c;如果你…

【论文精读】DMVSNet

今天读的是一篇发表在ICCV 2023上的文章&#xff0c;作者来自华中科技大学。 文章地址&#xff1a;点击前往 项目地址&#xff1a;Github 文章目录 Abstract1 Introduction2 Relative Work3 Motivation3.1 Estimated bias and interpolated bias3.2 One-sided V.S. Saddle-shap…

怎么做到高性能网络IO?

为什么要做高性能网络IO。主要是解决c10&#xff0c;c10M问题 最开始的时候我们走的内核协议栈&#xff0c;走内核协议栈其实性能比较低&#xff0c;因为我们之前介绍的时候需要拷贝两次 但是我们采用用户态协议栈可以少拷贝一次&#xff0c;可以大大提高效率&#xff0c; 步骤…

基于粒子群算法优化概率神经网络PNN的分类预测 - 附代码

基于粒子群算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于粒子群算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于粒子群优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络…

职业迷茫,我该如何做好职业规划

案例25岁男&#xff0c;入职2月&#xff0c;感觉自己在混日子&#xff0c;怕能力没有提升&#xff0c;怕以后薪资也提不起来。完全不知道应该往哪个方向进修&#xff0c;感觉也没有自己特别喜欢的。感觉自己特别容易多想&#xff0c;想多年的以后一事无成的样子。 我觉得这个案…

Tektronix(泰克)示波器TBS1102B测试电压

对于 Tektronix TBS1102B 示波器来说&#xff0c;测试电压的步骤基本如下&#xff1a; 连接测量点&#xff1a; 将被测电路的测量点连接到示波器的输入通道。使用正确的探头并确保连接的极性正确。 选择通道&#xff1a; 选择示波器上的通道&#xff0c;你想要测量的电压可能连…

20231112_DNS详解

DNS是实现域名与IP地址的映射。 1.映射图2.DNS查找顺序图3.DNS分类和地址4.如何清除缓存 1.映射图 图片来源于http://egonlin.com/。林海峰老师课件 2.DNS查找顺序图 3.DNS分类和地址 4.如何清除缓存

单链表按位序与指定结点 删除

按位序删除(带头结点) #define NULL 0 #include<stdlib.h>typedef struct LNode {int data;struct LNode* next; }LNode, * LinkList;//按位序删除&#xff08;带头结点&#xff09; bool ListInsert(LinkList& L, int i, int& e) {if (i < 1)return false;L…

【Spring Cloud】声明性REST客户端:Feign

Spring Cloud Feign ——fallback 服务降级 1. Feign 简介2. Feign 的基础使用2.1 普通 HTTP 请求2.2 Feign 远程调用上传文件接口 1. Feign 简介 Feign 是一个声明式的 HTTP 客户端&#xff0c;它简化了编写基于 REST 的服务间通信代码的过程。在 Spring Cloud 中&#xff0c…

如何从零开始手写一个消息中间件(从宏观角度理解消息中间件的技术原理)

如何从零开始手写一个消息中间件&#xff08;从宏观角度理解消息中间件的技术原理&#xff09; 什么是消息中间件消息中间件的作用逐一拆解消息中间件的核心技术消息中间件核心技术总览IOBIONIOIO多路复用AIOIO多路复用详细分析selectpollepoll Java中的IO多路复用 协议序列化消…

【算法每日一练]-快速幂,倍增,滑动窗口(保姆级教程 篇1) #麦森数 #青蛙跳

之前是考试准备&#xff0c;所以有几天没更新&#xff0c;今天开始继续更新 目录 快速幂模板 题目&#xff1a;麦森数 思路&#xff1a; 题目&#xff1a;青蛙跳 思路&#xff1a; 快速幂模板 #include <bits/stdc.h> #define ll long long using namespa…