C++笔记---类和对象

1. 类的定义

类是C++中的一种自定义类型,是某个具体事物或概念的抽象化代码表示,通过类的成员(变量+函数/方法),可以表征出事物或概念的特征。

1.1 类定义的格式

class Stack
{
public:// 成员函数void Init(int n = 4){array = (int*)malloc(sizeof(int) * n);if (nullptr == array){perror("malloc申请空间失败");return;}capacity = n;top = 0;}void Push(int x){// ...扩容array[top++] = x;}int Top(){assert(top > 0);return array[top - 1];}void Destroy(){free(array);array = nullptr;top = capacity = 0;}
private:// 成员变量int* array;size_t capacity;size_t top;
}; // 分号不能省略

class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省 略。类和C语言中的结构体类似,类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数/类函数。一般来说,这些类函数是专门设计来服务于这个类类型的变量(对象)。

为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面或者后面加_ 或者 m 开头,注意C++中这个并不是强制的,只是一些惯例,具体看公司的要求。

// _成员变量名
int* _array;
size_t _capacity;
size_t _top;// 成员变量名_
int* array_;
size_t capacity_;
size_t top_;// m成员变量名
int* mArray;
size_t mCapacity;
size_t mTop;

C++中struct也可以定义类,C++兼容C中struct的用法,同时struct升级成了类,明显的变化是 struct中可以定义函数,一般情况下我们还是推荐用class定义类。

定义在类中的成员函数默认为inline。

1.2 访问限定符

上面Stack类中的“public”和“private”就是访问限定符,除此之外,还有“protected”。

他们的作用是限定类成员被访问的权限。

• C++一种实现封装的方式,用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。

• public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private是一样的,以后继承章节才能体现出他们的区别。

• 访问权限作用域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为止,如果后面没有访问限定符,作用域就到 “}”即类结束。

• class定义成员没有被访问限定符修饰时默认为private,struct默认为public。

• 一般成员变量都会被限制为private/protected,需要给别人使用的成员函数会放为public。

习惯上,被public修饰的成员统一放到前面,被private修饰的成员统一放到后面。

被public修饰的一般是类函数,被private修饰的一般是成员变量。

1.3 类域

类定义了一个新的作用域,类的所有成员都在类的作用域中,在类体外定义成员时,需要使用 :: 作 用域操作符指明成员属于哪个类域。

前面提到,在类中定义的函数默认为inline函数,如果不希望某个函数被当作inline函数,则可将类函数的声明与定义分开,只在类中声明,而在类外进行定义。

class Stack
{
public:// 成员函数void Init(int n = 4);void Push(int x);int Top();void Destroy();
private:// 成员变量int* array;size_t capacity;size_t top;
}; // 分号不能省略void Stack::Init(int n = 4)
{array = (int*)malloc(sizeof(int) * n);if (nullptr == array){perror("malloc申请空间失败");return;}capacity = n;top = 0;
}
void Stack::Push(int x)
{// ...扩容array[top++] = x;
}
int Stack::Top()
{assert(top > 0);return array[top - 1];
}
void Stack::Destroy()
{free(array);array = nullptr;top = capacity = 0;
}

类域影响的是编译的查找规则,上面程序中的函数如果不指定类域Stack,那么编译器就把这些函数当成全局函数,那么编译时,找不到array等成员的声明/定义在哪里,就会报错。指定类域Stack,就是知道这些函数是成员函数,当前域找不到的array等成员,就会到类域中去查找。

2. 对象的定义(实例化)

简单来说,类只是一种类似于结构体的类型,用类类型定义出的变量,就是该类的对象。

2.1 实例化的概念

用类类型在物理内存中创建对象的过程,称为类实例化出对象。

类是对象进行的一种抽象描述,是一个模型一样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,用类实例化出对象时,才会分配空间。

一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。打个比方:类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,设计图规划了有多 少个房间,房间大小功能等,但是并没有实体的建筑存在,也不能住人,用设计图修建出房子,房 子才能住人。同样类就像设计图一样,不能存储数据,实例化出的对象分配物理内存存储数据。

以“Date类”为例:

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;
};

这里给出了定义“Date类”类型变量的蓝图,利用该类进行实例化,就可以得到“Date类”类型的变量。

int main()
{// Date类实例化出对象day1和day2Date day1;Date day2;return 0;
}

2.2 this指针

相信读者已经注意到,类函数看上去似乎有些奇怪:这些函数直接使用了类中的成员变量,而没有对应形参的传入,那么这些函数怎么知道成员变量是谁的呢?。

我们从类函数的调用方式入手:

int main()
{Date day1;day1.print(2024, 7, 29);Date day2;day2.print(2004, 12, 18);return 0;
}

因为类函数也是类的成员,所以使用成员访问操作符“.”访问对象的成员即可调用类函数。

可以看到,类函数的调用是与某个对象绑定在一起的,所以类函数能知道成员变量是哪个对象的。

但是,在底层上是如何做到的呢?

编译器编译后,类的成员函数默认都会在形参第一个位置,增加一个当前类类型的指针,叫做“this指针”。比如Date类的Init的真实原型为: 

void Init(Date* const this, int year, int month, int day);

所以,在调用类函数时,当前对象的地址就会通过“this指针”传入函数中,函数就能对该对象的成员变量进行操作。

类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值的语句相当于是:

 this->_year = year;

2.3 对象的大小

我们已经了解过C语言中结构体的大小C语言结构体的大小,结构体内存对齐_c语言 struct大小-CSDN博客

相比于结构体,类增加了成员函数,那么这些成员函数会使实例化出的对象的空间如何变化呢?

对于同一个类,不同的对象之间成员变量一般不同,但是成员函数完全相同。所以,没有单独为每一个对象存储成员函数的必要。其次,函数被编译后是一段指令,对象中没办法存储,这些指令 存储在一个单独的区域(代码段),那么对象中非要存储的话,也只能是成员函数的指针。同一个函数只有一个地址,也没有必要分别存储。最后,其实函数指针本身就是不需要存储的,函数指针是一个地址,调用函数被编译成汇编指令[call 地址], 其实编译器在编译链接时,就要找到函数的地址,不是在运行时找,只有动态多态是在运行时找,就需要存储函数地址,这个我们以后会讲解。

总结来说,每个类的对象的大小只与成员变量有关,成员函数不存储在对象中。在此基础上,符合内存对齐的原则。

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

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

相关文章

C语言从头学39——结构体位字段、弹性数组成员

1、struct位字段 位字段是C语言 struct 的一种特殊数据结构&#xff0c;它的属性&#xff08;这里称为字段&#xff09;由二进制位组成&#xff0c;适合操作二进制数据。每个属性的取值只有整数且不会出现负值&#xff0c;故数据类型为 unsigned int。 位字段结构…

大数据采集汇聚系统研究

大数据采集汇集系统是一种能够广泛收集、处理和存储来自多种数据源的海量数据的系统。该系统在现代企业管理和决策中发挥着至关重要的作用&#xff0c;为企业提供了强大的数据支持和分析能力。以下是对大数据采集汇集系统的详细介绍&#xff1a; 一、系统概述 大数据采集汇集…

八股文”在实际工作中是助力、阻力还是空谈?

“八股文”在实际工作中是助力、阻力还是空谈&#xff1f; 作为现在各类大中小企业面试程序员时的必问内容&#xff0c;“八股文”似乎是很重要的存在。但“八股文”是否能在实际工作中发挥它“敲门砖”应有的作用呢&#xff1f;有IT人士不禁发出疑问&#xff1a;程序员面试考…

Laravel序列化解码:深入Eloquent模型的序列化机制

Laravel序列化解码&#xff1a;深入Eloquent模型的序列化机制 引言 Laravel作为一门优雅的PHP Web开发框架&#xff0c;提供了许多便利的功能来简化开发过程。其中一个强大而易用的功能便是模型的序列化。序列化是将对象状态转换为可以存储或传输的格式的过程。在Laravel中&a…

DNS、网关、IP、DHCP

DNS、网关、IP、DHCP&#xff1a;深入剖析与理解 在计算机网络的世界中&#xff0c;DNS、网关、IP和DHCP是四个至关重要的概念&#xff0c;它们共同构建了互联网的基础架构&#xff0c;确保了数据的准确传输和设备的有效连接。本文将深入剖析这四个概念&#xff0c;帮助读者更…

《动手做科研 》| 03. 如何阅读人工智能研究论文

地址链接:《动手做科研》03. 如何阅读人工智能研究论文 导读: 在刚迈入科研时&#xff0c;人人都说读论文很重要&#xff0c;但是很少有人能完整地教你应该如何读论文。论文不仅揭示了行业的最新进展和趋势&#xff0c;而且为我们提供了改进技术和解决复杂问题的思路。然而&…

==和equals的区别以及为什么重写hashcode

对于基本数据类型是比较值&#xff0c;引用数据类型比较地址是否相等&#xff1b;equals一般是比较对象的地址&#xff0c;但是具体分析&#xff0c;如integer里面的equal&#xff0c;就是用里面的基本数据类型int的值取比较的。 integer缓存机制&#xff1a;用 a5,或者a Inte…

【JAVA】JAVA学习网站推荐

一、简介 为了让大家和自己不错过优质的JAVA学习网站&#xff0c;我会在不断的学习过程中补充完善此篇章&#xff1b; 二、推荐网站 1、大白菜导航 推荐理由&#xff1a;介绍java,又不止介绍java;智者见智吧&#xff1b; 后续更新中…

JDK-ForkJoinPool

归档 GitHub: JDK-ForkJoinPool JDK 版本 openjdk version "17.0.12" 2024-07-16 OpenJDK Runtime Environment Temurin-17.0.127 (build 17.0.127) OpenJDK 64-Bit Server VM Temurin-17.0.127 (build 17.0.127, mixed mode, sharing)测试 Slf4j public class Mi…

《学会 SpringBoot · 参数校验》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

经纬恒润天津研发中心实验室荣获CNAS权威认证

近日&#xff0c;经纬恒润天津研发中心实验室成功通过中国合格评定国家认可委员会(CNAS)的严格扩项评审&#xff0c;正式被授予CNAS认可证书。此次认证&#xff0c;是经纬恒润实验室在原有CNAS实验室基础上&#xff0c;再添天津研发中心这一重要检测阵地&#xff0c;是对经纬恒…

重生奇迹MU自由选择个性大师之路

自由选择大师技能 每一个大师职业都拥有三条大师技能树&#xff0c;每一条大师技能树对职业加强的侧重点各不相同。玩家可以根据自己喜欢专一选择&#xff0c;一条路走到底&#xff1b;当然也可以同时兼修两条或者三条技能树&#xff0c;做到雨露均沾。每一种选择都没有绝对的…

【linux】Linux中环境变量相关操作的详细教程及实战案例

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

实验2-3-2 计算摄氏温度

//实验2-3-2 计算摄氏温度#include<stdio.h> int main(){int C, F;scanf("%d",&F);C5*(F-32)/9;printf("Celsius %d",C);}

【Hive SQL】数据探查-数据抽样

文章目录 数据随机抽样1、随机数排序抽样&#xff08;rand()&#xff09;2、数据块抽样&#xff08;tablesample()&#xff09;3、分桶抽样 数据随机抽样 在大规模数据量的数据分析及建模任务中&#xff0c;往往针对全量数据进行挖掘分析时会十分耗时和占用集群资源&#xff0c…

kafka leader选举过程浅析

文章目录 概要核心概念leader选举具体流程小结 概要 kafka我们都知道它是通过副本机制&#xff0c;来支持负载均衡和故障转移等高可用的&#xff0c;那么具体副本的选举过程你了解吗&#xff1f;下面我们一起来学习下吧&#xff01; 核心概念 Controller定义&#xff1a;是特…

文献综述如何帮助研究人员避免现有研究的重复

VersaBot一键生成文献综述 进行良好的文献综述可以作为研究人员的有力工具&#xff0c;避免在多个方面重复现有研究&#xff1b; 1.揭示现有知识&#xff1a; 通过努力探索过去的研究&#xff0c;研究人员可以全面了解其领域中已经探索和建立的内容。这些知识使他们能够确定真…

linux系统iptable防火墙开放指定ip及端口

在Linux系统中&#xff0c;可以使用iptables命令来配置防火墙并开放指定IP的端口。下面是一些常用的命令示例&#xff1a; 1. 检查当前防火墙规则&#xff1a; iptables -L这个命令将列出当前的防火墙规则。 2. 开放TCP端口&#xff1a; iptables -A INPUT -s xxx.xxx.xxx.…

Linux基础操作(下)

软件安装&#xff0c;CentOS系统和Ubuntu是使用不同的包管理器 CentOS使用yum管理器&#xff0c;Ubuntu使用apt管理器 在CentOS系统中&#xff0c;使用yum命令联网管理软件安装 yum语法: yum [-y] [install | remove | search ] 软件名称 在Ubuntu系统中&#xff0c;使用apt命…

ShardingSphere实战(1)- 分库分表基础知识

一、为什么要分库分表 分库分表是一种数据库优化策略&#xff0c;主要用于解决大型应用或高并发场景下数据库性能瓶颈的问题。具体来说&#xff0c;分库分表可以带来以下好处&#xff1a; 提高性能&#xff1a; 减少单个数据库实例的负载&#xff0c;避免单点性能瓶颈。当数据…