「C++」类和对象1

news2024/10/6 8:32:35

🎇个人主页: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.coloradmin.cn/o/1258051.html

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

相关文章

CloudCompare 源码编译

一、下载源码 二、cmake 编译 这里面有四个比较重要的地方 1、源码的位置 2、生成的位置 3、项目的位置 4、qt 的位置 三、编译 开始测试&#xff0c;先用那个项目做测试 没有问题 然后用build的那个打开 加入Qt 的相关库到qcc中 启动项目生成cloudcompare 启动 ok ,完成…

阿里云ACE认证之国际版与国内版对比!

大厂疯狂裁员&#xff0c;互联网行业迎来寒冬&#xff0c;技术人员被动陷入疯狂内卷。在愈加内卷的IT领域&#xff0c;“云计算”作为少有的蓝海&#xff0c;无疑是打工人未来实现职场提升、摆脱内卷的绝佳选择&#xff01; 对于云计算行业的人来说&#xff0c;最值得考的肯定是…

守护机器智能时代,上海迅软科技终端防泄密方案横空出世!

客户简要介绍 某智能科技股份有限公司是一家专注于数字化、自动化和新能源的机器人公司。公司致力于为劳动密集程度比较高的行业制造有用且价格合理的机器人&#xff0c;目前已广泛应用于农业、园艺、施工、测绘和设施服务等领域。在新加坡、美国、瑞典、大陆及香港等多地有研发…

C++相关闲碎记录(1)

1、C绘制爱心图像 #include <iostream> #include <cmath>using namespace std;int main() {// 心形曲线公式 (x^2 y^2 - a)^3 - x^2*y^3 0double a 1;double bound 1.5 * sqrt(a);double step 0.05;for (double y bound; y > -bound; y - step) {for (do…

vue或uniapp中keep-alive的使用,(附带生命周期原理图)

什么是keep-alive&#xff1f; keep-alive是一个内置组件&#xff0c;用于缓存和管理组件的状态。 当 keep-alive包裹一个组件时&#xff0c;这个组件的状态将会被缓存起来&#xff0c;而不是每次重新渲染。这在多个视图之间切换时特别有用&#xff0c;可以避免重复的创建和销…

【Spring】Spring是什么?

文章目录 前言什么是Spring什么是容器什么是 IoC传统程序开发控制反转式程序开发理解Spring IoCDI Spring帮助网站 前言 前面我们学习了 servlet 的相关知识&#xff0c;但是呢&#xff1f;使用 servlet 进行网站的开发步骤还是比较麻烦的&#xff0c;而我们本身程序员就属于是…

leetcode:2864. 最大二进制奇数(python3解法)

难度&#xff1a;简单 给你一个 二进制 字符串 s &#xff0c;其中至少包含一个 1 。 你必须按某种方式 重新排列 字符串中的位&#xff0c;使得到的二进制数字是可以由该组合生成的 最大二进制奇数 。 以字符串形式&#xff0c;表示并返回可以由给定组合生成的最大二进制奇数。…

什么是闭包和作用域链?

1. 什么是闭包 闭包指的是那些引用了另一个函数作用域中变量的函数&#xff0c;通常是在嵌套函数中实现的。 举个栗子&#xff0c;createCounter 接受一个参数 n&#xff0c;然后返回一个匿名函数&#xff0c;这个匿名函数是闭包&#xff0c;它可以访问外部函数 createCounte…

Centos7上面部署redis

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

多集群部署中的 Kubernetes 弹性 (RTO/RPO)

啊&#xff0c;Kubernetes&#xff01;我们DevOps挑战的万灵药。 Kubernetes是一个开源的容器编排工具&#xff0c;本应加速软件交付、保护我们的应用程序、降低成本并减少我们的头痛问题&#xff0c;对吗&#xff1f; 不过说真的&#xff0c;Kubernetes已经彻底改变了我们编…

kali系统复现环境:Vulfocus 提示服务器内部错误,请联系管理员的解决方法

Linux-kali系统复现环境&#xff1a;Vulfocus&&提示服务器内部错误&#xff0c;请练习管理员的解决方法 第一步&#xff1a; 先下载docker和docker-compose apt-get update apt-get install docker apt-get install docker-compose输入如下图命令&#xff0c;有版本…

HarmonyOS应用开发者基础认证【题库答案】

HarmonyOS应用开发者高级认证【题库答案】 一、判断 首选项preferences是以Key-Value形式存储数据&#xff0c;其中Key是可以重复。&#xff08;错&#xff09;使用http模块发起网络请求时&#xff0c;必须要使用on(‘headersReceive’&#xff09;订阅请求头&#xff0c;请…

恒温恒湿试验设备故障维修指南

恒温恒湿试验设备是一种用于模拟特定温度和湿度条件下的环境的设备&#xff0c;通常用于测试产品在不同环境条件下的性能。设备可能会出现故障&#xff0c;导致温湿度控制不准确或其他问题。以下是一般的故障排除和维修指南&#xff0c;但请注意&#xff0c;具体的维修步骤可能…

01:编译lua及C调用

我们今天在windows平台编译lua&#xff0c;生成 lua动态库,lua.exe&#xff0c;luac.exe 我把这个目录上传到giee&#xff0c;使用下面命令获取它: git clone gitgitee.com:jameschenbo/lua_c_application.git 或者直接访问:访问网页 目录结构如下&#xff1a; build.cmd 是…

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

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

开发测试利器之Fiddler网络调试工具详细安装使用教程(包含汉化脚本)

一、Fiddler简介 Fiddler 是一款功能强大的网络调试工具&#xff0c;可以帮助开发人员和测试人员分析和调试网络流量。它通过截取计算机和服务器之间的HTTP/HTTPS请求&#xff0c;并提供详细的请求和响应信息来帮助我们理解和诊断网络通信。 Fiddler 可以用于各种用途&#x…

案例说法:智能网联车背后的安全隐患

随着汽车智能化、网联化的发展&#xff0c;汽车数据处理能力日益增强&#xff0c;未经授权对个人信息和重要数据采集、利用等数据安全问题逐步凸显。对车辆网络攻击、网络侵入等网络安全问题恐将危及个人生命安全、合法权益&#xff0c;甚至危害公共利益、国家安全&#xff0c;…

【活动回顾】sCrypt在柏林B2029开发者周

B2029 是柏林的一个区块链爱好者、艺术家和建设者聚会&#xff0c;学习、讨论和共同构建比特币区块链地方。 在2023年6月9日至11日&#xff0c;举行了第7次Hello Metanet研讨会。本次研讨会旨在为参与者提供一个学习、讨论和共同构建比特币区块链的平台。 在这个充满激情和创意…

js moment时间范围拿到中间间隔时间

2023.11.27今天我学习了如何对只返回的开始时间和结束时间做处理&#xff0c;比如后端返回了&#xff1a; [time:{start:202301,end:202310}] 我们需要把中间的间隔渲染出来。 [202301,202302,202303,202304,202305,202306,202307,202308,202309,202310] 利用moment的add进…

图解算法数据结构-LeetBook-树03_层序遍历奇数偶数行方向不同

一棵圣诞树记作根节点为 root 的二叉树&#xff0c;节点值为该位置装饰彩灯的颜色编号。请按照如下规则记录彩灯装饰结果&#xff1a; 第一层按照从左到右的顺序记录 除第一层外每一层的记录顺序均与上一层相反。即第一层为从左到右&#xff0c;第二层为从右到左。 示例 1&…