C++ 类与对象(类、实例化、this指针)

目录

一、前言

二、正文 

1.类和对象

1.1类定义格式

1.2访问限定符

1.3类域

2.实例化

2.1实例化概念

 2.2对象大小

3.this指针

三、结语


一、前言

前面我们已经了解了缺省参数和函数重载等,今天让我们来学习类与对象吧,因为类与对象的内容很多,所以我们迫不得已我们只能拆开几部分来讲。

二、正文 

1.类和对象

1.1类定义格式

  • Date为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省的,类体中内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。
  • 为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面或者后面加_或者 m 开头,注意C++中这个并不是强制的,只是一些惯例,具体看公司的要求
  • C++中struct也可以定义类,C++兼容C中struct的用法,同时struct升级成了类,明显的变化是stout中可以定义函数,一般情况下我们还是推荐用class定义类。
  • 定在类面的成员函数默认为inline。 
  • #include<iostream>
    using namespace std;
    class Date//Date是类的名字
    {
    public://public是访问限定符,后面我们会讲到。void Init(int year=2024,int month=11,int day=2)//Init是成员函数{_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
    private://private和public一样也是访问限定符。int _year;int _month;//_year/_month/_day都是成员变量int _day;
    };//分号不能省略。
    int main()
    {Date d1;d1.Init();d1.Print();return 0;//程序结果是成功打印:2024-11-2
    }
    #include<iostream>
    using namespace std;
    //这里我们简单写个单链表
    struct SList
    {SList* next;//如果在C语言中这里会报错,在C语言中这里的类型必须是struct SList//但是C++中并不需要这么写,struct的名称就是类型,如这里的SList。int data;int ADD(int x,int y)//除此之外,在C++中struct被升级成为了类,我们还可以在struct里面定义函数,如这里的ADD。{return x + y;}
    };int main()
    {return 0;
    }

1.2访问限定符

  •  C++一种实现封装的方式,用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
  •  public修饰的成员在类外可以直接被访问;protected和private修饰的成员在类外不能直接被访问,protected和private是一样的,以后继承章节才能体现出他们的区别。
  •  访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止,如果后面没有访问限定符,作用域就到 } 即类结束。
  • class定义成员没有被访问限定符修饰时默认为private, struct默认为public。
  • 一般成员变量都会被限制为private/protected,需要给别人使用的成员函数会放为public。

所以访问限定符共有三个:public,private,protected。

由上面两张图可以看出,当private修辞成员变量时,成员变量在类外面无法被访问。

但是当成员变量没有private修辞时,在类外面可以被访问。

其实只要是private修辞的内容都不能在类外面访问,同理当一个成员函数被private修辞时,在类外面也访问不了这个成员函数。

1.3类域

  • 类定义了一个新的作用域,类的所有成员都在类的作用域中,在类体外定义成员时,需要使用  ::  作用域操作符指明成员属于哪个类域。
  • 类域影响的是编译的查找规则,下面程序中Init如果不指定类域Stack,那么编译器就把Init当成全局函数,那么编译时,找不到array等成员的声明/定义在哪里,就会报错。指定类域Stack,就是知道init是成员函数,当前域找不到的array等成员,就会到类域中去查找。 
#include<iostream>
using namespace std;
class Stack
{
public: void Init(int n = 4);
private:int* array;int capacity;int top;
};
void Stack::(int n)
{array = (int*)malloc(sizeof(int) * n);//arry是被private修辞过的,不能在类外面访问,这里是错误示范。if (nullptr == array){perror("malloc 申请空间失败!");return;}capacity = n;top = 0;//同理capacity和top同上面arry一样,都是不能在类外面访问的。
}
int main()
{Stack st;st.Init();return 0;
}

因此,函数最好完整的定义在类里面,因为在类外面完成函数功能的话,需要涉及成员变量部分,因为成员变量被private修辞,在类外面找不到成员变量,编译器就会报错。

2.实例化

2.1实例化概念

  •  用类类型在物理内存中创建对象的过程,称为类实例化出对象。
  • 类是对象进行一种抽象描述,是一个模型一样的东西,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,用类实例化出对象时,才会分配空间。
  • 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量。打个比方:类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,设计图规划了有多少个房间,房间大小功能等,但是并没有实体的建筑存在,也不能住人,用设计图修建出房子,房子才能住人。同样类就像设计图一样,不能存储数据,实例化出的对象分配物理内存存储数据。

#include<iostream>
using namespace std;
class Date
{
public:void Init(int year=2024,int month=11,int day=2){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;//其实这里只是声明对象,并没有实质的开空间。int _month;int _day;
};
int main()
{//这里通过类的实例化,实例化出了d1和d2。Date d1;Date d2;printf("%d\n", sizeof(d1));//d1和d2的大小都是12return 0;
}

 2.2对象大小

分析一下类对象中哪些成员呢?类实例化出的每个对象,都有独立的数据空间,所以对象中肯定包含成员变量,那么成员函数是否包含呢?首先函数被编译后是一段指令,对象中没办法存储,这些指令存储在一个单独的区域(代码段),那么对象中非要存储的话,只能是成员函数的指针。再分析一下,对象中是否有存储指针的必要呢,Date实例化d1和d2两个对象,d1和d2都有各自独立的成员变量_year/_month/_day存储各自的数据,但是d1和d2的成员函数Init/Print指针却是一样的,存储在对象中就浪费了。如果用Date实例化100个对象,那么成员函数指针就重复存储100次,太浪费了。这里需要再额外哆嗦一下,其实函数指针是不需要存储的,函数指针是一个地址,调用函数被编译成汇编指令[call地址],其实编译器在编译链接时,就要找到函数的地址,不是在运行时找,只有动态多态是在运行时找,就需要存储函数地址,这个我们以后会讲解。

上面那么一段话的总结就是:类中成员函数不占空间,实例化对象的大小只与成员变量有关。如下图:

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

对这部分忘记或不熟悉的小伙伴们可以看看我们往期关于这部分知识的分享:https://blog.csdn.net/yiqingaa/article/details/136966545?sharetype=blog&shareId=136966545&sharerefer=APP&sharesource=yiqingaa&sharefrom=link

#include<iostream>
using namespace std;
class A
{
public:void Print(){cout << _ch << endl;}
private:char _ch;int _i;
};
class B
{
public:void Print(){}
};
class C
{};
int main()
{cout << sizeof(A) << endl;// 8cout << sizeof(B) << endl;// 1cout << sizeof(C) << endl;// 1return 0;
}

上面的程序运行后,我们看到没有成员变量的B和C对象的大小是1,为什么没有成员变量还要给1个字节呢?因为如果1个字节都不给,还怎么证明对象存在过呢!所以还是给1字节,纯粹是为了占位标识对象存在。

3.this指针

  • Date类中有Init与 Print两个成员函数,函数体中没有关于不同对象的区分,那当d1调用Init和Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这里就要看到C++给了一个隐含的this指针解决这里的问题
  • 编译器编译后,类的成员函数默认都会在形参第一个位置,增加一个当前类类型的指针,叫做this 指针。比如Date类的Init的真实原型为,void Init(Date* const this, int year,int month, int day)
  • 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值,this->_year = year;
  • C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使用this指针。 
#include<iostream>
using namespace std;
class Date
{
public://实质: void Init(Date* const this,int year=2024,int month=11,int day=2)void Init(int year=2024,int month=11,int day=2){_year = year;//可以写: this->_year=year;_month = month;//可以写: this->_month=month;_day = day;//可以写: this->_day=day;//this不可以出现在实参和形参中出现,但可以在函数体中出现。}
private:int _year;int _month;int _day;
};
int main()
{Date d1;printf("%d\n", sizeof(d1));return 0;
}
#include<iostream>
using namespace std;
class Date
{
public://实质: void Init(Date* const this,int year=2024,int month=11,int day=2)void Init(int year=2024,int month=11,int day=2){this->_year=year;this->_month=month;this->_day=day;//this不可以出现在实参和形参中出现,但可以在函数体中出现。}
private:int _year;int _month;int _day;
};
int main()
{Date d1;printf("%d\n", sizeof(d1));return 0;
}

三、结语

今天的分享就到此结束了,小伙伴们要是对你有所帮助的话,帮忙给个三连,作者在这谢谢啦。当然也欢迎大佬们的指正,拜拜~

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

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

相关文章

【jvm】为什么Xms和Xmx的值通常设置为相同的?

目录 1. 说明2. 避免性能开销3. 提升稳定性4. 简化配置5. 优化垃圾收集6. 获取参数6.1 代码示例6.2 结果示例 1. 说明 1.-Xms 和 -Xmx 参数分别用于设置堆内存的初始大小&#xff08;最小值&#xff09;和最大大小。2.在开发环境中&#xff0c;开发人员可能希望快速启动应用程…

element-plus校验单个form对象合法性

在 Vue 中&#xff0c;循环生成的表单列表&#xff0c;并且每个表单中包含多个对象&#xff0c;使用 v-for 来创建这些表单&#xff0c;并且使用动态 prop 路径来验证单个对象是否满足必填校验。 <template><el-form ref"formRef" :model"form" …

大模型面试题:Prefix LM和Causal LM的区别是啥?

获取更多面试真题的集合&#xff0c;请移步至 https://pica.zhimg.com/80/v2-7fd6e77f69aa02c34ca8c334870b3bcd_720w.webp?sourced16d100b 说白了&#xff1a;就是attention mask不一样&#xff0c;如下所示&#xff1a; img 它们定义如下&#xff1a; Prefix LM&#xff…

学习虚幻C++开发日志——定时器

官方文档&#xff1a;虚幻引擎中的Gameplay定时器 | 虚幻引擎 5.5 文档 | Epic Developer Community | Epic Developer Community 定时器 安排在经过一定延迟或一段时间结束后要执行的操作。例如&#xff0c;您可能希望玩家在获取某个能力提升道具后变得无懈可击&#xff0c;…

mac终端运行 MySQL语句 和服务器相关命令

文章目录 1.mac服务器相关命令1.获取mac电脑的IP 2.MySQL语句1. 退出 MySQL&#xff1a;2.使用新密码连接&#xff1a;3.创建一个新数据库&#xff1a;4.查看数据库列表&#xff1a;5.使用数据库&#xff1a;6.创建一个用户表&#xff1a;7.插入数据8.查询数据9.更新数据10.删除…

Windows达梦8数据库:本地编码:PG_GBK, 导入文件编码:PG_UTF8错误最优解决方法

在windows使用达梦8DM管理工具直接导入.dmp文件(可能是从Linux导出的)时出现该错误 错误如下 解决方案如下&#xff1a; 1、重新建立UTF-8编码的数据库 2、新建一个模式 3、使用CMD 命令进行导入 找到DM数据库的安装路径的bin 目录下 cmd 进入终端&#xff0c;使用命令&…

【极客兔兔-Web框架Gee详解】Day0 序言

文章目录 一、Web 开发1. 什么是Web 开发&#xff1f;2. 主要组成部分2.1 前端开发2.2 后端开发2.3 全栈开发2.4 数据库管理 3. Web开发过程3.1 规划和设计&#xff1a;3.2 开发和编码&#xff1a;3.3 测试和优化&#xff1a;3.4 部署和维护&#xff1a; 4. 总结 二、用标准库n…

Java入门(8)--反射机制

Java反射机制&#xff1a;运行时的强大工具 &#x1f50d; &#x1f3af; 掌握Java反射&#xff0c;让你的代码更具灵活性和扩展性&#xff01; 在上一篇文章中&#xff0c;我们学习了Java网络编程的相关知识。今天&#xff0c;让我们深入探讨Java反射机制&#xff0c;了解如何…

Aurora 64b/66bIP核学习

本文作为在学习使用aurora IP核的道路上&#xff0c;找到的一些对该IP讲解比较详细的资料&#xff0c;记录下来&#xff0c;便于日后翻阅&#xff0c;温故知新。 Aurora IP的特点 Aurora 协议在 2002 年由 Xilinx 公司首次提出&#xff0c;是由Xilinx提供的一个开源、免费的链…

树叶分类竞赛(Baseline)以及kaggle的GPU使用

树叶分类竞赛(Baseline)-kaggle的GPU使用 文章目录 树叶分类竞赛(Baseline)-kaggle的GPU使用竞赛的步骤代码实现创建自定义dataset定义data_loader模型定义超参数训练模型预测和保存结果 kaggle使用 竞赛的步骤 本文来自于Neko Kiku提供的Baseline&#xff0c;感谢大佬提供代码…

服务器作业(2)

架设一台NFS服务器&#xff0c;并按照以下要求配置 关闭防火墙 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 配置文件设置&#xff1a; [rootlocalhost ~]# vim /etc/exports 1、开放/nfs/shared目录&#xff0c;供所有用户查询资料 共享…

014:无人机遥控器操作

摘要&#xff1a;本文详细介绍了无人机遥控器及其相关操作。首先&#xff0c;解释了油门、升降舵、方向舵和副翼的概念、功能及操作方式&#xff0c;这些是控制无人机飞行姿态的关键部件。其次&#xff0c;介绍了美国手、日本手和中国手三种不同的操作模式&#xff0c;阐述了遥…

Redis的持久化以及性能管理

目录 一、Redis持久化概述 1.什么是Redis持久化 2.持久化方式 3.RDB持久化 3.1概念 3.2触发条件 3.3执行流程 3.4启动时加载 4. AOF持久化 4.1概念 4.2启动AOF 4.3执行流程 4.4启动时加载 5.RDB和AOF的优缺点 二、Redis性能管理 1.查看Redis内存使用 2…

什么是JS的垃圾回收机制?

在JavaScript中&#xff0c;垃圾回收&#xff08;Garbage Collection&#xff0c;简称GC&#xff09;是一种自动内存管理机制。它的主要任务是识别并回收不再被使用的对象&#xff0c;以释放内存空间。以下是关于JavaScript垃圾回收机制的详细解释&#xff1a; 标记清除算法 …

Java项目实战II基于Java+Spring Boot+MySQL的高校办公室行政事务管理系统(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在高等教育…

HTB:PermX[WriteUP]

目录 连接至HTB服务器并启动靶机 1.How many TCP ports are listening on PermX? 使用nmap对靶机TCP端口进行开放扫描 2.What is the default domain name used by the web server on the box? 使用curl访问靶机80端口 3.On what subdomain of permx.htb is there an o…

nginx安装ssl模块教程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、openssl是什么&#xff1f;二、ssl证书免费申请地址三、安装步骤1.nginx安装ssl模块 总结 一、openssl是什么&#xff1f; OpenSSL 不仅是一个独立的工具包,它…

在Vue和OpenLayers中使用移动传感器实现飞机航线飞行模拟

项目实现的核心代码 项目概述 该项目的目标是使用Vue.js作为前端框架&#xff0c;结合OpenLayers用于地图显示&#xff0c;实时获取来自手机传感器的数据&#xff08;如经纬度、高度、速度&#xff09;来模拟飞机在地图上的飞行轨迹。整体架构如下&#xff1a; Vue.js 用于构建…

分析 SQL 语句的一般步骤

analyse-sql 数据库的性能调优是一个很大的话题。但是对于开发人员来讲&#xff0c;掌握一些常用的 SQL 优化手段却不是什么难事。 从本章节开始&#xff0c;将连载总结常用的适合于开发人员的 SQL 优化手段与大家分享。 要想解决性能优化的问题&#xff0c;首先要想办法发现哪…

数据库基础(2) . 安装MySQL

0.增加右键菜单选项 添加 管理员cmd 到鼠标右键 运行 reg文件 在注册表中添加信息 这样在右键菜单中就有以管理员身份打开命令行的选项了 1.获取安装程序 网址: https://dev.mysql.com/downloads/mysql/ 到官网下载MySQL8 的zip包, 然后解压 下载后的包为: mysql-8.0.16-…