【类和对象】类的作用域 | 类的实例化 | 类对象模型 | this指针

news2024/12/28 19:29:35

目录

5.类的作用域

6.类的实例化

6.1成员的声明和定义 

6.2实例化出的对象大小

7.类对象模型❗❗

7.1如何计算类对象的大小

7.2类对象的存储方式猜测

7.3结构体内存对齐规则

7.3.1内存对齐

7.3.2大小端  

8.this指针

8.1this指针的引出

8.2this指针的特性

C和C++实现栈的对比


  • 类,对象,成员变量,变量,成员函数的关系

5.类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。

  • 类域能解决一定的命名冲突问题
  • 在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
//声明.h
class Person
{
public:
	void PrintPersonInfo();
private:
	char _name[20];
	char _gender[3];
	int  _age;
};

//定义.cpp
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
	cout << _name << " " << _gender << " " << _age << endl;
}

6.类的实例化

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

  • 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员。
  • 定义出一个类并没有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。
  •  一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
  • 类是没有空间的,只有类的实例化出的对象才有具体的空间。

举例:

  • 类就像谜语一样,对谜底来进行描述,谜底就是谜语的一个实例。
  • 谜语:"年纪不大,胡子一把,主人来了,就喊妈妈" 谜底:山羊

举例:做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。

 

6.1成员的声明和定义 

  • 无论是成员变量/成员函数在类中,只要还未被实例化成对象,那么它们都是一种声明,因为它们只是类,并不存在空间。
  • 定义并不是给值,而是为类开辟空间,也就是实例化。
  • 定义的时候可以初始化,但是只初始化并不代表定义。
#include<stdlib.h>
#include<iostream>
using namespace std;
class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	//这里是声明还是定义?声明
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date s;//定义了
	s.Init(1,1,1);
❌	Date::_year++;//不能因为它只是声明,并没有开辟空间
❌  Date._month = 100;  // 编译失败:error C2059: 语法错误:“.” 
	return 0;
}

6.2实例化出的对象大小

 移步☞类对象的存储方式。

7.类对象模型❗❗

《深度探索C++对象模型》这本书中对对象模型的描述如下:

有两个概念可以解释C++对象模型:

  • 语言中直接支持面向对象程序设计的部分。
  • 对于各种支持的底层实现机制。

对象模型是指在面向对象编程中,为了描述和处理现实世界中的实体、事物或概念所构建的抽象模型。它通常由类、对象、属性、方法等元素组成,用于描述实体之间的关系、结构和行为。


❓❓问题:类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?类对象的存储方式?如何计算一个类的大小? 下面我们来一起探讨。

7.1如何计算类对象的大小

  • 类的实例化=对象
  • sizeof(类名)
  • sizeof(对象)
  • 二者计算都是类实例化的大小,也就是类对象的大小。
  • 一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐
  • 注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象
  • 没有成员变量的类对象大小1字节,标识对象实例化,定义出来存在。
class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
	}
private:
	int _a;
	char _i;
};

❓计算下面类对象的大小: sizeof(A1) : ______ sizeof(A2) : ______ sizeof(A3) : ______

#include<stdlib.h>
#include<iostream>
using namespace std;
// 类中既有成员变量,又有成员函数
//内存对齐存储
class A1 {
public:
	void f1() {}
private:
	int _a;
	char _i;
};

// 类中仅有成员函数
//标识对象实例化,定义出来存在
class A2 {
public:
	void f2() {}
};

// 类中什么都没有---空类
class A3
{};
int main()
{
	cout << sizeof(A1) << endl;
	cout << sizeof(A2) << endl;
	cout << sizeof(A3) << endl;
	return 0;
}

7.2类对象的存储方式猜测

类对象的存储方式有两种:

  • 对象中包含类的各个成员(不用)
  • 代码只保存一份,在对象中保存存放代码的地址(以后)
  • 只保存成员变量,成员函数存放在公共的代码段(现阶段)
//现阶段
class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2;

	//不是一块空间,成员变量各自是各自的空间
	d1._year;
	d2._month;

	//是一块空间,成员函数是一块空间
	d1.Init(1,1,1);
	d2.Init(1,1,1);

	return 0;
}

 【对象中包含类的各个成员】

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


 【代码只保存一份,在对象中保存存放代码的地址】


 【只保存成员变量,成员函数存放在公共的代码段】

7.3结构体内存对齐规则

1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

  • 注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
  • VS中默认的对齐数为8。

3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。


【面试题】

  • 1. 结构体怎么对齐? 为什么要进行内存对齐?
  • 2. 如何让结构体按照指定的对齐参数进行对齐?能否按照3、4、5即任意字节对齐?
  • 3. 什么是大小端?如何测试某机器大端还是小端,有没有遇到过要考虑大小端的场景。
  • 前面C语言进阶我们也讲解过(结构体)C语言之自定义类型_结构体篇(1)-CSDN博客

7.3.1内存对齐

  • 怎样内存对齐?
  • 类对象的包含了什么,需要包括成员函数吗?
  • 为什么要内存对齐?
  • 可以改变对齐参数吗?

【怎么内存对齐---按照规则】 

类的对象存储空间只包含了成员变量,成员函数在公共区域。 

#include<iostream>
using namespace std;
struct A
{
private:
	int _a;
	char _i;
};

struct B
{
private:
	char _i;
	int _a;
};

 【为什么要内存对齐】

  • 对齐是为了提高效率!
  • 硬件规定CPU一次只能读取4/8个字节。
  • 32/64个线,32/64个位,组成0/1的二进制数。(消耗相同,一次只读取32/64位,4/8个字节)
  • 硬件规定:CPU的控制器只能从整数倍开始读取。起始位置必须是整数倍的位置。
  • 以上规定从而导致了:对齐和不对齐读取存在效率上的问题。
  • 对齐读取的次数比不对齐读取的次数多。

【对齐可以改变编译器默认对齐数的大小】

#include<iostream>
using namespace std;

//改变默认对齐数的大小
#pragma pack(1)//相当于不对齐

struct A
{
private:
	int _a;
	char _i;
};


struct B
{
private:
	char _i;
	int _a;
};

int main()
{
	cout << sizeof(A) << endl;
	cout << sizeof(B) << endl;
	return 0;
}

7.3.2大小端  

8.this指针

8.1this指针的引出

8.2this指针的特性

C和C++实现栈的对比

【C语言】

可以看到,在用C语言实现时,Stack相关操作函数有以下共性:

  • 每个函数的第一个参数都是Stack*
  • 函数中必须要对第一个参数检测,因为该参数可能会为NULL
  • 函数中都是通过Stack*参数操作栈的
  • 调用时必须传递Stack结构体变量的地址

结构体中只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据方式是分离开,而且实现上相当复杂一点,涉及到大量指针操作,稍不注意可能就会出错。 


【C++】感谢祖师爷

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

【C语言实现】

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int DataType;
typedef struct Stack
{
	DataType* array;
	int capacity;
	int size;
}Stack;
void StackInit(Stack* ps)
{
	assert(ps);
	ps->array = (DataType*)malloc(sizeof(DataType) * 3);
	if (NULL == ps->array)
	{
		assert(0);
		return;
	}
	ps->capacity = 3;
	ps->size = 0;
}
void StackDestroy(Stack* ps)
{
	assert(ps);
	if (ps->array)
	{
		free(ps->array);
		ps->array = NULL;
		ps->capacity = 0;
		ps->size = 0;
	}
}
void CheckCapacity(Stack* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity * 2;
		DataType* temp = (DataType*)realloc(ps->array,
			newcapacity * sizeof(DataType));
		if (temp == NULL)
		{
			perror("realloc申请空间失败!!!");
			return;
		}
		ps->array = temp;
		ps->capacity = newcapacity;
	}
}
void StackPush(Stack* ps, DataType data)
{
	assert(ps);
	CheckCapacity(ps);
	ps->array[ps->size] = data;
	ps->size++;
}
int 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;
}
int main()
{
	Stack s;
	StackInit(&s);
	StackPush(&s, 1);
	StackPush(&s, 2);
	StackPush(&s, 3);
	StackPush(&s, 4);
	printf("%d\n", StackTop(&s));
	printf("%d\n", StackSize(&s));
	StackPop(&s);
	StackPop(&s);
	printf("%d\n", StackTop(&s));
	printf("%d\n", StackSize(&s));
	StackDestroy(&s);
	return 0;
}

【C++实现】 

#include<iostream>
using namespace std;

typedef int DataType;
class Stack
{
public:
	void Init()
	{
		_array = (DataType*)malloc(sizeof(DataType) * 3);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		_capacity = 3;
		_size = 0;
	}
	void Push(DataType data)
	{
		CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	void Pop()
	{
		if (Empty())
			return;
		_size--;
	}
	DataType Top() { return _array[_size - 1]; }
	int Empty() { return 0 == _size; }
	int Size() { return _size; }
	void Destroy()
	{
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_array, newcapacity *
				sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};
int main()
{
	Stack s;
	s.Init();
	s.Push(1);
	s.Push(2);
	s.Push(3);
	s.Push(4);
	printf("%d\n", s.Top());
	printf("%d\n", s.Size());
	s.Pop();
	s.Pop();
	printf("%d\n", s.Top());
	printf("%d\n", s.Size());
	s.Destroy();
	return 0;
}

🙂感谢大家的阅读,若有错误和不足,欢迎指正。

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

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

相关文章

面试官:volatile如何保证可见性的,具体如何实现?

写在开头 在之前的几篇博文中&#xff0c;我们都提到了 volatile 关键字&#xff0c;这个单词中文释义为&#xff1a;不稳定的&#xff0c;易挥发的&#xff0c;在Java中代表变量修饰符&#xff0c;用来修饰会被不同线程访问和修改的变量&#xff0c;对于方法&#xff0c;代码…

TortoiseSVN 报错:The server unexpectedly closed the connetion

前言 CentOS7Linux 安装subversionmod_dav_svn&#xff0c;搭建subversion(svn)服务器 The server unexpectedly closed the connetion 解决办法 重启Apache服务 shell> systemctl restart httpd

Day1-力扣刷题学习打卡

1、两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以…

如何理解Linux文件IO?

一、文件IO的概述 1、什么是文件&#xff1f; Linux下一切皆文件。普通文件、目录文件、管道文件、套接字文件、链接文件、字符设备文件、块设备文件。 2、什么是IO&#xff1f; input output&#xff1a;输入输出 3、什么是文件IO&#xff1f; 对文件的输入输出&#xff0c;把…

Transformers 直观解释——不仅是如何工作,而且为什么工作得这么好 (Ketan Doshi)

Transformers 直观解释——不仅是如何工作&#xff0c;而且为什么工作得这么好 Transformers Explained Visually — Not Just How, but Why They Work So WellHow does the input sequence reach the Attention module 输入序列如何到达Attention模块Each input row is a word…

条件队列大法好:wait和notify的基本语义

条件队列是我们常用的轻量级同步机制&#xff0c;也被称为“waitnotify”机制。但很多刚刚接触并发的朋友可能会对wait和notify的语义和配合过程感到迷惑。 今天从join()方法的实现切入&#xff0c;重点讲解wait()方法的语义&#xff0c;简略提及notify()与notifyAll()的语义&…

ubuntu安装docker的详细教程

检查卸载老版本docker ubuntu下自带了docker的库,不需要添加新的源。 但是ubuntu自带的docker版本太低,需要先卸载旧的再安装新的。 注:docker的旧版本不一定被称为docker,docker.io 或 docker-engine也有可能,所以卸载的命令为: sudo apt-get remove -y docker docke…

记录工作中莫名其妙的bug

1、问题&#xff1a;办公室的电脑突然除了我之外&#xff0c;都不能访问我们的线上系统了 原因&#xff1a;因为是内网&#xff0c;同事有刚刚升级了Windows11&#xff0c;配置的DNS被清了&#xff0c;还有同事换了公司的新电脑&#xff0c;还没有配DNS 位于&#xff1a;C /Win…

JVM虚拟机:通过jconsole远程连接解决JVM报错

本文重点 前面我们介绍过的一些工具都是使用命令行的方式来帮助我们完成&#xff0c;本文我们将使用一种图形化界面的方式来远程连接&#xff0c;然后完成关于JVM的检测任务。 jconsole jconsole是一个JVM的检测工具&#xff0c;这个工具任何安装了Java的电脑上都有的&#…

亚信安慧AntDB:简化开发与运维

AntDB将SQL作为唯一语法&#xff0c;不仅简化了开发运维&#xff0c;更提高了数据库的易用性。这种统一的语法规范让开发人员在编写和优化复杂的查询时更加得心应手&#xff0c;极大地提高了工作效率。随着数据库系统的不断发展&#xff0c;AntDB的独特设计理念使得用户可以更加…

三连杆滑块机构运动学仿真 | 【Matlab源码+理论公式文本】

【程序简介】&#x1f4bb;&#x1f50d; 本程序通过matlab实现了三连杆滑块机构的运动学仿真编程&#xff0c;动态展现了三连杆机构的运动动画&#xff0c;同时给出了角位移、角速度和角加速度的时程曲线&#xff0c;除了程序本身&#xff0c;还提供了机构运动学公式推导文档…

Centos7安装Clickhouse单节点部署

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

【力扣白嫖日记】1934.确认率

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1934.确认率 表&#xff1a;Signups 列名类型user_idinttime_stampdatetime User_id是该表的主键。每一行都…

线性回归 quickstart

构建一元一次方程 100个&#xff08;X, y &#xff09;&#xff0c;大概是’y3x4’ import numpy as npnp.random.seed(42) # to make this code example reproducible m 100 # number of instances X 2 * np.random.rand(m, 1) # column vector y 4 3 * X np.random…

4.10.CVAT——3D对象标注

文章目录 1. 创建任务2. 3D 任务工作区3.标准 3D 模式 Standard 3D mode4. 用长方体进行注释4.1. 用shapes进行注释4.2. 使用长方体进行跟踪Tracking 使用 3D 注释工具来标记 3D 对象和场景&#xff0c;例如车辆、建筑物、景观等。 1. 创建任务 要创建 3D 任务&#xff0c;您必…

PS学习-抠图-蒙版-冰块酒杯等透明物体

选中图&#xff0c;ctrlA 全选 ctrlC复制 创建一个蒙版图层 选中蒙版Alt 点击进入 ctrlv 复制 ctrli 反转 原图层 ctrldelete填充为白色 添加一个背景&#xff0c;这个方法通用 首选创建一个 拖到最底部 给它填充颜色 这个可能是我图片的原因。视频是这样做的

《古滇传说水龙吟》敖诀扮演者李亚云

2024年2月28日&#xff0c;演员李亚云参演新剧古滇传说原创系列剧第一部《水龙吟》在浙江横店影视城开机拍摄。该剧由中共昆明市西山区委宣传部、石林县委宣传部、昆明滇池国家旅游度假区管委会文旅投促局、云南民族电影制片厂、云南卫视、昆明影视拍摄服务中心支持&#xff0c…

8:00面试,8:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到9月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

BMP280 arduino调试

终于成功了。 #include <SPI.h> //定义数据类型 #define s32_t long signed int #define u32_t long unsigned int #define u16_t unsigned short #define s16_t signed short // 定义从设备选择引脚 const int chipSelectPin 10; //定义BMP280寄存器/// unsigned int …

Java面向对象案例之描述专业和学生(4)

类的方法图 学生类&#xff1a; 属性&#xff1a;学号&#xff0c;姓名&#xff0c;年龄&#xff0c;所学习的专业方法&#xff1a;学习的方法&#xff0c;描述学习状态。描述内容包括姓名、学号、年龄、所学习的专业信息 专业类&#xff1a; 属性&#xff1a;专业编号&#xf…