【C++】类和对象(一)

前言:在前面我们带大家初步步入了C++,让大家大概知道了他的样子,那今天就可以说我们要正式步入C++的大门了,这一章内容的细节比较多各位学习的时候一定要仔细。

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:高质量C++学习 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


目录标题

  • 类和对象
    • 什么是对象
    • 什么是类
      • 定义类的格式:
      • 类的访问限定符
      • 封装
      • 类的作用域
      • 类的实例化
      • 类的对象的大小计算
        • 对象的存储方式
    • this指针
      • this指针的引出


类和对象

C++中,类是一种自定义的数据类型,用于封装数据和相关的操作。对象是类的实例,通过实例化类来创建对象。
类包含了属性(成员变量)和方法(成员函数),用于描述对象的状态和行为。成员变量是类的数据成员,用于存储对象的数据;成员函数是类的操作成员,用于实现对象的行为。

什么是对象

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题,而在C++中C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成,通俗的理解C语言好比送外卖我们需要关注如何下单如何拿,而C++只需要关注如何点外卖。

什么是类

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。比如:之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量;

定义类的格式:

class 类的名称
{	//类体:成员变量--属性  成员函数---功能
}

现在以C++方式实现,会发现struct中也可以定义函数,但在C++中类的定义通过关键字class来实现。以下是一个简单的类的定义示例:

  1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
class Date//C++中的定义方式
{
public://限定符void Init(int year,int month,int day){_year = year;_month = month;_day = day;}void Print(){cout <<"year = " << _year <<" month = " << _month <<" day = " << _day << endl;}//成员变量在这里声明(并未开辟空间)并没有定义,开了空间才是定义
private://限定符int _year;int _month;int _day;
};struct Date1//C语言的定义方式
{int _year;int _month;int _day;
};int main()
{Date dl;//定义类dl.Init(2024, 1, 30);//在c++中引用类的函数可以直接和C语言一样加.即可dl.Print();return 0;
}
  1. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名
  2. 这里作者在强调一个点,我们上面这种定义函数的形式是为了平常方便练习,如果我们引用了头文件在头文件定义的话用下面这种形式进行定义
  3. 类是可以直接引用内部的函数,就像C语言中引用成员变量一样,直接在后面加.即可
//定义放在类的实现文件Person.cpp中
#include "Person.h"
void Person::Init(int year,int month,int day){_year = year;_month = month;_day = day;
}

在上面这个例子中我们可以看到,C++中定义的类中我们可以放入函数,而C语言不可以,这个我们在后面马上会讲到,在然后各位肯定看到了这里怎么有个publicprivate这又是什么东西,那么我们接下来就会给大家讲解这两个是用来干嘛的。


类的访问限定符

在这里插入图片描述

  1. public修饰的成员在类外可以直接被访问
  2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  4. 如果后面没有访问限定符,作用域就到 } 即类结束。
  5. class的默认访问权限为private,struct为public(因为struct要兼容C)
  6. :C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。注意:在继承和模板参数列表位置,struct和class也有区别,后序给大家介绍。

封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。(初学阶段我个人理解对这个有个大概的概念即可)


类的作用域

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

class Date
{
public:void Init(int year,int month,int day); void Print();
private:int _year;int _month;int _day;
};void Date::Init(int year, int month, int day)//这里需要指定Init是属于Date这个类域
{_year = year;_month = month;_day = day;
}
void Date::Print()//同理这里需要指定Print属于Date这个域
{cout << "year = " << _year << " month = " << _month << " day = " << _day << endl;
}int main()
{Date dl;dl.Init(2024, 1, 30);dl.Print();return 0;
}

因此在次强调在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
在这里插入图片描述


类的实例化

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

  1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没
    有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。类就像谜语一样,对谜底来进行描述,谜底就是谜语的一个实例。谜语:“年纪不大,胡子一把,主人来了,就喊妈妈” 谜底:山羊
  2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量。
  3. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间

以下是一些示例代码来演示如何实例化类:

#include <iostream>class MyClass 
{
public:void myMethod() {std::cout << "Hello, World!" << std::endl;}
};int main() {// 实例化类的对象MyClass obj;// 调用类的方法obj.myMethod();return 0;
}

类的对象的大小计算

我们来看看下面这段代码,类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大小?

class A
{
public:
void PrintA()
{cout<<_a<<endl;
}
private:char _a;
};

代码分析:

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

在这里插入图片描述
为什么会是1呢?我们这里就可以猜测一下难到说那个函数是不算类的空间中的大小了嘛?答案是肯定的。那么我们将讲解一下对象的存储方式

对象的存储方式
  1. 每个对象只保存成员变量,成员函数指针(指针)存放在公共的代码段保存
    在这里插入图片描述

  2. 不同的对象,成员变量是不同的,但是成员函数是完全相同的,都是执行的一模一样的函数代码,此时成员函数就不需要存放在对象中,而应该存放在公共代码区。

  3. 当对象调用成员函数的时候,是去公共代码区找的,而不是去存放对象的空间里面找。
    4.一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象,至于其余的成员变量就和结构体的对齐规则一致如果有不懂的可以看我之前的博客结构体对齐规则。


this指针

this指针的引出

我们来看下面这个代码:

class Date
{
public:void Init(int year,int month,int day){_year = year;_month = month;_day = day;}void Print(){cout << "year = " << _year << " month = " << _month << " day = " << _day << endl;}   
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2;d1.Init(2024, 1, 30);d2.Init(2025, 2, 32);d1.Print();d2.Print();return 0;
}

上面我们定义了两个对象,那么我们在都调用InitPrint函数的时候,编译器又是如何区分是d1和d2两个对象分别的初始化和打印的呢?
这里我们就要提到一个叫做this指针的概念:
因为C++中通过引入this指针解决了该问题,在C++中,this指针是一个隐含的指针,它指向当前对象的地址。当一个类的成员函数被调用时,编译器会自动地将当前对象的地址作为this指针传递给该成员函数。通过this指针,我们可以在成员函数中访问当前对象的成员变量和成员函数。所以刚刚初始化的代码和打印的代码本质上是这样的:


class Date
{
public:void Init(int year,int month,int day){this->_year = year;//本质上是有一个this指针指向了成员变量this->_month = month;this->_day = day;}void Print(){cout << "year = " << this->_year << " month = " << this->_month << " day = " << this->_day << endl;}   
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2;d1.Init(&d1,2024, 1, 30);//这里只是为了方便大家理解,才写的取地址,实际写的过程中不需要前面这&d1d2.Init(&d2,2025, 2, 32);d1.Print();d2.Print();return 0;
}

接下来我们再来看几道面试的经典题目:
例1:下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行

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

代码分析:
这个主函数我们乍一看怎么p是指向的空指针,空指针又指向了Print这个函数,这里我们第一反应肯定是 这空指针传过去能不报错嘛?我们仔细思考一下,这里本质上虽然是传递了空指针的地址,但是是this指针接收了空指针,为什么会报错?所以这里无非是对象的地址是空而已并不会报错。
运行结果
在这里插入图片描述
我们在来验证一下我们的想法

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

我们在这里在函数部分判断一下传过来的是否是空指针,运行结果如下,因此原本的程序并不会报错只是传递的是空指针。在这里插入图片描述


例题2:下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行

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

代码分析:这里我们可以看到和刚刚一样传递了空指针过去,但是这次不同的是我们又要访问成员变量,可是空指针怎么可以访问成员变量呢?空指针是不能解引用的这里我们在C语言的指针和结构体阶段都有过学习,这里就不在过多解释了,因此这个代码是错误的。


这里我们再次对this指针做一个总结:

  1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
  2. 只能在“成员函数”的内部使用
  3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给
    this形参。所以对象中不存储this指针。
  4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递.

好啦,今天的内容就到这里啦,下期内容预告类和对象(二)构造函数、析构函数等等


结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


🌏🗺️ 这里祝各位寒假愉快 💞💞

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

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

相关文章

Flink实战三_TableAPISQL

接上文&#xff1a;Flink实战二_DataStream API 1、Table API和SQL是什么&#xff1f; 接下来理解下Flink的整个客户端API体系&#xff0c;Flink为流式/批量处理应用程序提供了不同级别的抽象&#xff1a; 这四层API是一个依次向上支撑的关系。 Flink API 最底层的抽象就是有…

AR眼镜_ar智能眼镜显示方案|光学方案

AR眼镜是一种智能眼镜&#xff0c;能够将虚拟现实和现实世界相结合&#xff0c;使人们能够在日常生活中体验和参与虚拟现实。然而&#xff0c;AR智能眼镜的制造成本高&#xff0c;开发周期长。要实现AR眼镜的各项功能&#xff0c;需要良好的硬件条件&#xff0c;而AR智能眼镜的…

大专生能不能学习鸿蒙开发?

目前安卓有2,000万的开发者。本科及以上学历占比为35%&#xff1b;iOS有2,400万开发者&#xff0c;本科及以上学历占比为40% 绝大多数的前端开发者都是大专及以下学历&#xff0c;在2023年华为开发者大会上余承东透露华为的开发者目前有200万&#xff0c;但鸿蒙开发者统计的数据…

【Lazy ORM 整合druid 实现mysql监控】

Lazy ORM 整合druid 实现mysql监控 JDK 17 Lazy ORM框架地址 up、up欢迎start、issues 当前项目案例地址 框架版本描述spring-boot3.0.7springboot框架wu-framework-web1.2.2-JDK17-SNAPSHOTweb容器Lazy -ORM1.2.2-JDK17-SNAPSHOTORMmysql-connector-j8.0.33mysql驱动druid-…

Mac截图软件CleanShot X为什么不能识别文字?CleanShot X文字识别教程

好多朋友在使用CleanShot X for Mac截图软件过程中发现不能进行OCR文字识别&#xff1f;其实这是因为你没有给CleanShot X相应的权限导致的&#xff0c;具体操作如下&#xff1a; 第一步、打开&#xff0c;系统偏好设置-隐私与安全设置-完全磁盘访问权限 点击左下方➕ 在应用程…

vue2 国际化的使用,自动翻译文件,自动生成国际化文件

vue2 国际化的使用&#xff0c;自动翻译文件&#xff0c;自动生成国际化文件 npm i vue-i18n6 文件代码 // zh.js 用来写全局通用的国际化 export default {home:"首页" }//en.js 用来写全局通用的国际化 export default {home:"home page" }//kor.js …

Security ❀ HTTP/HTTPS逐包解析交互过程细节

文章目录 1. TCP三次握手机制2. HTTP Request 请求报文3. HTTP Response 响应报文4. SSL/TLS协议4.1. ClientHello 客户端Hello报文4.2 ServerHello 服务器Hello报文4.3. *ServerKeyExchange 服务公钥交换4.4. ClientKeyExchange 客户端公钥交换4.5. *CertificateVerify 证书验…

蓝桥杯---九数组分数

1,2,3 ... 9 这九个数字组成一个分数,其值恰好为1/3,如何组法? 下面的程序实现了该功能,请填写划线部分缺失的代码。 注意,只能填写缺少的部分,不要重复抄写已有代码。不要填写任何多余的文字。 代码 public class _05九数组分数 {public static void test(int[] x){int a …

[网鼎杯 2018]Fakebook1

join一个用户后&#xff0c;点进去发现是这样的 查看这个页面的源代码&#xff0c;发现一个base64编码后的字串 decode之后就是我们join新用户时填入的blog网址 那我们是不是可以通过填入存储flag的地址&#xff0c;从而回显出来呢&#xff1f;当然&#xff0c;先按照常规sqli…

C语言应用实例——贪吃蛇

&#xff08;图片由AI生成&#xff09; 0.贪吃蛇游戏背景 贪吃蛇游戏&#xff0c;最早可以追溯到1976年的“Blockade”游戏&#xff0c;是电子游戏历史上的一个经典。在这款游戏中&#xff0c;玩家操作一个不断增长的蛇&#xff0c;目标是吃掉出现在屏幕上的食物&#xff0c…

物联网IOT视频设备如何快速对接阿里云生活物联网(Link Visual)并成功上云?

原文永久更新地址&#xff1a;https://www.yundashi168.com/472.html 文章来源&#xff1a;猿视野 如果有图片看不清楚&#xff0c;加载不出来&#xff0c;请阅读原文。 什么是Link Visual、 Link Visual是生活物联网平台针对视频产品推出的增值服务&#xff0c;提供视频数据上…

第一节 分布式架构设计理论与Zookeeper环境搭建

目录 1. 分布式架构设计理论 1. 分布式架构介绍 1.1 什么是分布式 1.2 分布式与集群的区别 1.3 分布式系统特性 1.4 分布式系统面临的问题 2. 分布式理论 2.1 数据一致性 2.1.1 什么是分布式数据一致性 2.1.2 副本一致性 2.1.3 一致性分类 2.2 CAP定理 2.2.1 CAP定…

Habitat环境学习二:导航任务中的Habitat-sim基础Habitat-sim Basics for Navigation

导航任务在Habitat-sim任务中的实现 官方教程概述重要概念1、Hello World程序1.0.1 基础设置Basic settings1.0.2 模拟器设置Configurations for the simulator1.0.3 创建模拟器实例1.0.4 初始化Agent1.0.5 导航和探索 官方教程 Habitat是一个高效的真实的3D模拟器&#xff0c…

【C++进阶】STL容器--list使用迭代器问题分析

目录 前言 1. list的基本使用 1.1 list构造函数 1.2 list迭代器 1.3 list capacity 1.4 list元素访问 1.5 list 修改操作 insert erase swap resize clear 2. list失效迭代器问题 3. list使用算法库函数问题 总结 前言 list&#xff08;链表&#xff09;在C中非常重要…

OpenAI发布新模型!ChatGPT性能重磅提升,API大幅降价,GPT-4 「变懒」被修复

OpenAI 对ChatGPT进行了大更新&#xff1a;推出了新一代的嵌入模型&#xff0c;对GPT-4 Turbo模型进行了更新&#xff0c;并将很快对GPT-3.5 Turbo的API进行大幅降价&#xff0c;GPT-4「变懒」行为也被修复。 接下来二狗就带大家看看ChatGPT的这次详细更新。 推出新的嵌入模型…

Shell中sed编辑器

1.简介 sed是一种流编辑器&#xff0c;流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。 sed编辑器可以根据命令来处理数据流中的数据&#xff0c;这些命令要么从命令行中输入&#xff0c;要么存储在一个 命令文本文件中。 2.sed编辑器的工作流程 sed…

Adobe Photoshop 2024 v25.4.0 - 专业的图片设计软件

Adobe Photoshop 2024 v25.4.0更新了&#xff0c;从照片编辑和合成到数字绘画、动画和图形设计&#xff0c;任何您能想象到的内容都能通过PS2024轻松实现。 利用人工智能技术进行快速编辑。学习新技能并与社区分享您的工作。借助我们的最新版本&#xff0c;做令人惊叹的事情从未…

【C/C++ 05】快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序算法&#xff0c;其基本思想是&#xff1a;任取待排序序列中的某元素作为基准值&#xff0c;按照该基准值将待排序集合分割成两个子序列&#xff0c;左子序列中所有元素均小于基准值&#xff0c;右子序列中所有元素均大于…

uniapp H5 实现上拉刷新 以及 下拉加载

uniapp H5 实现上拉刷新 以及 下拉加载 1. 先上图 下拉加载 2. 上代码 <script>import DragableList from "/components/dragable-list/dragable-list.vue";import {FridApi} from /api/warn.jsexport default {data() {return {tableList: [],loadingHi…

路由反射器 RR 配置实验

一、预习&#xff1a; RR&#xff1a;Route Reflect&#xff0c;是为了解决 IBGP 水平分割问题&#xff0c;即&#xff1a;【BGP 路由器从 IBGP 收到的路由&#xff0c;不会传递给其他 IBGP 邻居】&#xff0c;因此需要使用路由反射器&#xff0c;这样&#xff0c;未收到路由的…