「C++」类和对象1

🎇个人主页:Ice_Sugar_7
🎇所属专栏:C++启航
🎇欢迎点赞收藏加关注哦!

文章目录

  • 🍉前言:初识面向对象
  • 🍉类
    • 🍌类的定义
    • 🍌访问限定符
      • 🥝类的作用域
    • 🍌类的封装
    • 🍌类的实例化
    • 🍌访问对象的成员
    • 🍌计算对象的大小
      • 🥝补充:内存对齐的意义
  • 🍉成员函数的this指针
  • 🍉写在最后

🍉前言:初识面向对象

C++是一门面向对象的语言,关注解决问题的对象各个对象之间的关系。比如用洗衣机洗衣服,对象就是人、洗衣机、衣服、洗衣液。洗衣服的过程就是这四个对象交互完成的:人把洗衣液倒进洗衣机,然后把衣服放进去。不用关心具体是怎么浸泡、洗多久等问题。通过建立各对象之间的关系,就可以解决问题了

🍉类

在初阶数据结构中,我们实现栈时使用结构体,并在里面定义数组、栈顶、容量等变量。但是C语言中结构体无法定义函数,而在C++中,结构体升级为类,可以在里面定义函数,不过一般我们用class来定义类

🍌类的定义

class className
{// 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号

class为定义类的关键字,ClassName为类名,{}中为类的主体

类里面可以定义函数(成员函数,又称为方法),比如你要实现一个栈,在C语言中只能写在全局,而在C++中可以直接写在类里面。这样会带来什么好处呢?你写初始化函数、入栈函数的时候参数部分就不用写栈了。此外,在类里面定义的函数默认是内联函数,不过由于内联函数是否展开取决于编译器的处理,所以一般建议短的函数在类里面定义,长的函数就放个声明,即声明与定义分离。

(类也是一个域,同名函数只有在同一个域里面才会重载)

🍌访问限定符

class当中有三种访问限定符:

public修饰的成员在类外可以直接被访问
protectedprivate修饰的成员在类外不能直接被访问

(在学到继承之前,可以认为protected约等于private)
class中不使用访问限定符的话默认所有成员都是private,而struct为了兼容C语言,默认所有成员都是public

类定义的惯例是:一般情况下,成员变量都是私有的。不过这不是硬性规定,还是要根据实际情况进行调整。

🥝类的作用域

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

访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现或类结束时为止

🍌类的封装

面向对象有三大特性:封装继承多态
在类和对象阶段,主要是研究类的封装特性。所谓封装,就是将数据操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互
其实就是把一个复杂的东西包装起来,只留下简单、方便操作的部分给使用者使用。比如:对于电脑这样一个复杂的设备(对象),提供给用户的就只有开机键、键盘、显示器、USB插孔等(对外公开接口),让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件(对象的属性和实现细节)它们被封装起来。对于计算机使用者而言,不用关心内部核心部件,只需知道怎么开机、怎么通过键盘和鼠标与计算机进行交互即可

🍌类的实例化

类的实例化指的是用类类型创建对象的过程

类是对对象进行描述,就像一个模型,限定了类有哪些成员。定义出一个类并没有分配实际的内存空间来存储它,而类实例化出的对象,占用实际的物理空间,存储类成员变量
关于类和对象的关系,有一个形象的比喻:一个类相当于是一栋房子的设计图,设计图肯定不能直接住人的(即类里面不能存数据),只有用设计图建出来房子才可以住人。而一个设计图可以建出多栋房子,一个类也可以对应多个对象。

对象里面只存成员变量,不存函数,因为所有对象的函数都是一样的,如果一个对象存储1个函数,那么100个对象就需要存储100个一样的函数,很浪费空间。因此,我们直接把函数放到公共的区域(公共代码区
(再举一例,这就好比一个小区,每个住户都有一套房,但是篮球场、泳池这些总不可能一户配一个吧?那就很逆天了)

补充:
区分变量是声明还是定义只需看是否有给它开一块空间,若没有则是声明。声明的变量是不能直接给它赋值的,因为赋值的前提是这个变量有空间

🍌访问对象的成员

访问成员其实和访问结构体成员大差不差了。如果是类,那就通过点运算符.访问;若是类的指针,则用箭头运算符->。这里不多赘述。

🍌计算对象的大小

计算大小涉及到学习结构体时的内存对齐的规则,先来回顾一下:

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

前面说过,成员函数并不在对象里面,所以只需计算成员变量的大小就ok了。

class Date {
public:void Print() {cout << _year << "." << _month << "." << _day << endl;}private:int _year;int _month;int _day;
};

比如这个日期类,显然它的大小就是12个字节:三个int 分别占0 1 2 3,4 5 6 7,8 9 10 11(这里的数字就是相对类起始地址的偏移量)

另外,无成员变量的类,对象大小为一个字节,这个字节不存储有效数据(有点像链表的哨兵位),只是用来标识定义的对象存在过。只有成员函数的类也是这样,因为成员函数并不在对象里面

🥝补充:内存对齐的意义

内存对齐通过规定变量所占用的内存空间的大小,使数据在内存中按照一定的规律排列,尽可能地减少内存控制器读取内存单元的次数(内存控制器一次只能读取一个内存单元,读取次数越多,访问速度就越低),从而提高存储器访问的效率和速度。


🍉成员函数的this指针

前面提到,成员函数是公共的,而每个对象调用同一个函数,如果对象之间成员变量不同的话,一般就会得到不同的结果,也就是说,成员函数可以识别不同对象的成员变量。可是有的函数根本没有参数,那是怎么识别出来呢?
比如说现在有一个日期的类,初始化之后可以打印日期,在主函数中定义了d1d2两个对象,并且都调用Init这个函数,但是函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

class Date {
private:int _year;int _month;int _day;public:void Init(int year, int month, int day) {_year = year;_month = month;_day = day;}void Print() {cout << _year << "-" << _month << "-" << _day << endl;}};int main() {Date d1,d2;d1.Init(2023, 11, 25);d1.Print();d2.Init(2024, 11, 25);d2.Print();return 0;
}

在这里插入图片描述
因为C++编译器在每个非静态成员函数的参数添加了一个this指针并将其隐藏起来(既然this是函数的参数,那么它就存在栈帧上),该指针指向当前对象(哪个对象调用这个函数,this就指向谁),在函数体中所有“成员变量”的操作,都是通过该指针去访问。比如d1调用Init函数,那么this指针就指向d1。实际效果就是这样:

void Init(int year, int month, int day) {this->_year = year;this->_month = month;this->_day = day;
}int main() {Date d1,d2;d1.Init(this, 2023, 11, 25);d1.Print();return 0;
}

(参数部分默认存在指针,所以你不要再人为添加上去,否则会报错)

然后来说一个重要的点,因为我们也会通过指针来调用成员函数,此时this指向的是这个指针所指向的对象,而非指针本身
(举个栗子)

class MyClass {
public:void printAddress() {cout << "Address of this object is: " << this << endl;}
};int main() {MyClass obj1;MyClass* obj2 = &obj1;obj1.printAddress();obj2->printAddress();return 0;
}

在这里插入图片描述
可以看到这两个的地址是一样的,其实都是对象obj1的地址

注意:对象的指针访问成员函数(方法)时,箭头运算符(->)表示访问,而非解引用,因为方法的地址并不在指针所指的对象里面
比如下面这段程序,表面上看p是空指针,不能解引用,但实际上是在访问函数,所以可以打印出结果,不会报错。

class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}

在这里插入图片描述
补充
(p虽然为空,但它也并非毫无作用,因为它指向A类的对象,那么成员函数Print也应该在A类之中,编译链接的时候就会到A这个类里面找一下有没有这个函数,如果没有那就会报编译错误;若有,并且声明和定义分离的话,就会去找函数的地址。换而言之,p可以为编译器指明去A类中找Print函数

下面这个虽然和上面的很像,但是程序崩了:

class A
{ 
public:void PrintA() {cout<<_a<<endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}

为啥崩了呢?因为打印_a时,其实就是打印this->_a,而this是空指针,对它解引用程序自然就崩咯


🍉写在最后

以上就是本篇文章的全部内容了,如果觉得本文对你有所帮助的话,那不妨点个小小的赞哦!(比心)

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

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

相关文章

动态规划专题——背包问题

&#x1f9d1;‍&#x1f4bb; 文章作者&#xff1a;Iareges &#x1f517; 博客主页&#xff1a;https://blog.csdn.net/raelum ⚠️ 转载请注明出处 目录 前言一、01背包1.1 使用滚动数组优化 二、完全背包2.1 使用滚动数组优化 三、多重背包3.1 使用二进制优化 四、分组背包…

Codeforces Round 911 (Div. 2) --- D题题解

D. Small GCD Problem - D - Codeforces 题目大意&#xff1a; 给你一个数组&#xff0c;你可以在里面任选三个数ai aj ak&#xff0c;要求i j k 互不相同&#xff0c; 现定义一个函数f(a,b,c)gcd(a,b)&#xff0c;其中a 和 b为a&#xff0c;b&#xff0c;c中较小的两个。求f…

大数据平台/大数据技术与原理-实验报告--MapReduce编程

实验名称 MapReduce编程 实验性质 &#xff08;必修、选修&#xff09; 必修 实验类型&#xff08;验证、设计、创新、综合&#xff09; 综合 实验课时 2 实验日期 2023.10.30-2023.11.03 实验仪器设备以及实验软硬件要求 专业实验室&#xff08;配有centos7.5系统…

【代码随想录刷题】Day18 二叉树05

文章目录 1.【513】找树左下角的值1.1题目描述1.2 解题思路1.2.1 迭代法思路1.2.2 递归法思路 1.3 java代码实现1.3.1 迭代法java代码实现1.3.2 递归法java代码实现 2. 【112】路径总和2.1题目描述2.2 解题思路2.3 java代码实现 3.【106】从中序与后序遍历序列构造二叉树3.1题目…

Linux | Linux入门及常用基础命令介绍

关注CodingTechWork Linux Linux介绍 概述 Linux出现的时候是没有图像化界面&#xff0c;都是黑屏操作&#xff0c;靠命令来完成操作&#xff0c;如磁盘读写、网络管理等。企业级服务器的维护基本都通过跳板机ssh到对应的服务器上进行操作&#xff0c;一般无图形化界面。 远…

DevEco Studio对同一套HarmonyOS代码进行多设备端预览

鸿蒙代码有一个很大的优势 不需要其他的语法 只需要一套HarmonyOS代码 就可以在 手机 平板 电脑上运行 我们可以在DevEco Studio预览器上 点击如下图指向位置 弹出的这个窗口中 我们将右上角的开关勾选上 这样 我们调试器向下滚动 就可以看到多端预览的一个效果了

开源与闭源:数字时代大模型之辩

欢迎大家到我的博客浏览更多文章。YinKais Blog | YinKais Blog 大模型的未来&#xff1a;开源与闭源的博弈 在大模型的发展中&#xff0c;开源和闭源两种截然不同的开发模式发挥着重要的作用。开源以其技术共享的特性&#xff0c;吸引了大量人才参与&#xff0c;推动了大模型的…

Windows Server 2012R2 修复CVE-2016-2183(SSL/TLS)漏洞的办法

一、漏洞说明 Windows server 2012R2远程桌面服务SSL加密默认是开启的,且有默认的CA证书。由于SSL/ TLS自身存在漏洞缺陷,当开启远程桌面服务,使用漏洞扫描工具扫描,发现存在SSL/TSL漏洞。远程主机支持的SSL加密算法提供了中等强度的加密算法,目前,使用密钥长度大于等于5…

队列实现方式、效率分析及应用场景

文章目录 一、什么是队列二、队列特性阻塞和非阻塞有界和无界单向链表和双向链表 三、Java队列接口继承图四、Java队列常用方法五、队列实现方式与效率分析六、队列的应用场景七、Python中队列与优先级队列使用 一、什么是队列 队列是一种特殊的线性表&#xff0c;遵循先入先出…

express习惯养成小程序-计算机毕设 附源码 32209

习惯养成小程序的设计与实现 摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;习惯养成小程序被用户普遍使…

WebSocket协议在java中的使用

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

Centos7上面部署redis

Centos7上面部署redis 编写这个部署redis&#xff0c;只是为了另一个文章入侵redis做准备&#xff0c;网上还有好多类似的文章&#xff0c;这个单纯的就是部署安装&#xff0c;并简单的测试使用以下 关联其他文章 [1]VMware上面安装部署centos7镜像系统【详细含镜像】 [2]血的教…

美女骑士开箱VELO Angel TT,银色天使,无痛骑行

阳光、女孩、自行车&#xff0c;脸上的笑容或明媚&#xff0c;或神秘&#xff0c;或青涩&#xff0c;在这个时候&#xff0c;世界上没有什么比骑行女孩更美的了&#xff01;      在北京&#xff0c;有一个热爱骑行的女孩&#xff0c;名叫季思铭&#xff0c;目前是中国农业…

CDA一级备考思维导图

CDA一级备考思维导图 第一章 数据分析概述与职业操守1、数据分析概念、方法论、角色2、数据分析师职业道德与行为准则3、大数据立法、安全、隐私 CDA一级复习备考资料共计七个章节&#xff0c;如需资料&#xff0c;请留言&#xff0c;概览如下图&#xff1a; 第一章 数据分析…

【Java】使用IntelliJ IDEA搭建SSM(MyBatis-Plus)框架并连接MySQL数据库

步骤 0 准备工作1 创建Maven项目2 配置Maven依赖3 配置数据源4 项目结构5 创建实体类6 创建数据访问层7 创建服务层8 创建Controller层9 启动项目10 使用Postman测试接口 0 准备工作 下载并安装 IntelliJ IDEA下载并安装 MySQL 数据库下载并安装Postman测试工具使用 Navicat 创…

WebSocket了解

一.什么是WebSocket WebSocket是HTML5下一种新的协议&#xff08;websocket协议本质上是一个基于tcp的协议&#xff09;它实现了浏览器与服务器全双工通信&#xff0c;能更好的节省服务器资源和带宽并达到实时通讯的目的Websocket是一个持久化的协议 二.websocket的原理 web…

CentOS 系列:CentOS 7 使用 virt-install + vnc 图形界面/非图形界面 创建虚拟机

CentOS 7 使用 virt-install + vnc 图形界面/非图形界面 创建虚拟机 一. 使用 virt-install + vnc 图形界面 创建虚拟机环境1、安装qemu-kvm,libvirt2、安装virt-install3、启动 librvirt4、网络配置5、安装虚拟机6、启动虚拟机7、如果安装时没记住IP,可以通过以下方法找…

Linux4.5、进程状态

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 进程状态介绍 Linux下具体进程状态 R状态 和 S状态 D状态 T状态 t状态 Z状态 X状态 进程状态介绍 首先&#xff0c;进程状态有运行&#xff0c;阻塞&#xff0c;挂起&#xff0c;这些只是一个大体的概括&am…

判断 一个整数 是不是 2 的阶次方

问题&#xff1a;判断 一个整数 是不是 2 的阶次方 思路&#xff1a; 1、先用while循环&#xff0c;判断该数字是否大于1 2、大于1&#xff0c;那么进行取模2&#xff0c;判断该数字是否是偶数 3、是偶数&#xff0c;那么除以2&#xff0c;看能不能整除掉&#xff0c;整除到最…

python 输出日志到文件,删除过期文件

参考&#xff1a;python logging模块按日期打印日志&#xff0c;并删除过期的日志 官方&#xff1a;15.7. logging — Logging facility for Python — Python 2.7.18 documentation 一 简单日志打印&#xff1a; import logging logging.basicConfig(levellogging.DEBUG,fo…