【C++初阶(五)类和对象(上)】

news2024/11/23 3:57:34

本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。

💓博主csdn个人主页:小小unicorn
⏩专栏分类:C++
🚚代码仓库:小小unicorn的代码仓库🚚
🌹🌹🌹关注我带你学习编程知识

C++初阶(五)

  • 面向过程和面向对象的初步认识
  • 类的引入
  • 类的定义
    • 类的两种定义方式:
    • 成员变量命名规则的建议:
  • 类的访问限定符及类的封装
    • 类的访问限定符
  • 类的封装
  • 类的作用域
  • 类的实例化
  • 类的对象模型
    • 如何计算类对象的大小
    • 类对象的存储方式猜测
    • 结构体内存对齐规则
  • this指针
    • this指针的引出
    • this指针的特性

面向过程和面向对象的初步认识

首先我们先给出以下结论:
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面向对象的,关注的是对象,将一件事拆分成不同的对象,靠对象之间的交互完成。

举例说明面向过程和面向对象的区别
在这里插入图片描述
在这里插入图片描述

我们就外卖系统来看看面向过程和面向对象之间的区别:
 面向过程,我们的关注点应该是用户下单、骑手接单以及骑手送餐这三个过程。
 面向对象,那我们的关注点应该就是客户、商家以及骑手这三个类对象之间的关系。

类的引入

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。

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

struct Test
{
	//成员变量
	int a;
	double b;
	//成员函数
	int Add(int x, int y)
	{
		return x + y;
	}
};

但上面结构体的定义,在C++中更喜欢用class来代替。

类的定义

class className
{
	//类体:由成员变量和成员函数组成

};  //注意后面的分号

其中class为定义类的关键字,className为类的名字,{}中为类的主体,注意定义结束时加上后面的分号。

 类中的元素称为类的成员:类中的数据称为类的属性或者成员变量,类中的函数称为类的方法或者成员函数。

类的两种定义方式:

1.声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
在这里插入图片描述

2.类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
在这里插入图片描述
一般情况下,更期望采用第二种方式。

成员变量命名规则的建议:

我们看看这个函数,是不是很僵硬?

class Date
{
public:
 void Init(int year)
 {
 // 这里的year到底是成员变量,还是函数形参?
 year = year;
 }
private:
 int year;
};

所以一般都建议这样:

class Date
{
public:
	void Init(int year)
	{
		_year = year;
	}
private:
	int _year;
};

或者这样:

class Date
{
public:
 void Init(int year)
 {
 mYear = year;
 }
private:
 int mYear;
};

其他方式也可以的,主要看公司要求。一般都是加个前缀或者后缀标识区分就行

类的访问限定符及类的封装

类的访问限定符

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

在这里插入图片描述
访问限定符说明

  1. public修饰的成员在类外可以直接被访问
  2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  4. 如果后面没有访问限定符,作用域就到 } 即类结束。
  5. class的默认访问权限为private,struct为public(因为struct要兼容C)

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

面试题
问题:C++中struct和class的区别是什么?

解答:C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类默认访问权限是private。

注意:在继承和模板参数列表位置,struct和class也有区别。

类的封装

面向对象的三大特性:封装、继承、多态。

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。

封装本质上是一种管理,让用户更方便使用类。比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。

在这里插入图片描述
对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。

在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。

类的作用域

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

class Person
{
public:
	//显示基本信息
	void ShowInfo();
private:
	char* _name;  //姓名
	char* _sex;   //性别
	int _age;     //年龄
};

//这里需要指定ShowInfo是属于Person这个类域
void Person::ShowInfo()
{
	cout << _name << "-" << _sex << "-" << _age << endl;
}

类的实例化

用类类型创建对象的过程,称为类的实例化。
1、类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。

就像C语言中定义了一个结构体一样,当你还未用该自定义类型创建变量时,定义结构体类型这个过程并没有分配实际的内存空间来存储它。

2、一个类可以实例化出多个对象,实例化出的对象将占用实际的物理空间来存储类成员变量。

就像你在C语言中定义了一个结构体,然后用该自定义类型创建了一个变量,那么这个变量将占用实际的物理空间来存储其成员变量。

3、类实例化出对象就像现实中使用建筑设计图建造出房子,类就是设计图。
在这里插入图片描述

设计图只设计出需要什么东西,但是并没有实体的建筑存在。同样类也只是一个设计,只有实例化出的对象才能实际存储数据,占用物理空间。
在这里插入图片描述

类的对象模型

如何计算类对象的大小

一个类当中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?类的大小又是如何计算的呢?

class Person
{
public:
	//显示基本信息
	void ShowInfo()
	{
		cout << _name << "-" << _sex << "-" << _age << endl;
	}
public:
	char* _name;  //姓名
	char* _sex;   //性别
	int _age;     //年龄
};

类对象的存储方式猜测

猜测一:对象中包含类的各个成员
在这里插入图片描述

缺陷:每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同的代码保存了多次,浪费空间。
猜测二:只保存成员变量,成员函数存放在公共的代码段。
在这里插入图片描述

在这里插入图片描述

对于上述两种存储方式,计算机是按照哪种方式来存储的,我们可以通过对下面的不同对象分别获取大小来进行分析:

// 类中既有成员变量,又有成员函数
class A1 {
public:
	void f1(){}
private:
	int _a;
};
// 类中仅有成员函数
class A2 {
public:
	void f2() {}
};
// 类中什么都没有---空类
class A3
{};

测试结果:
在这里插入图片描述

通过单目操作符sizeof来获取这三个对象的大小,结果A1的大小为4个字节,A2的大小为1个字节,A3的大小也为1个字节。

结论:一个类的大小,实际就是该类中“成员变量”之和,当然也要进行内存对齐,注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类(占位)。

结构体内存对齐规则

1.第一个成员在与结构体变量偏移量为0的地址处。(即结构体的首地址处,即对齐到0处)

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

3.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

4.对齐数 = 该结构体成员变量自身的大小与编译器默认的一个对齐数的较小值。

this指针

this指针的引出

我们先来定义一个日期类的Date:

#include <iostream>
using namespace std;
class Date
{
public:
	void Display()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	void SetDate(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	Date d1, d2;//实例化两个日期类
	d1.SetDate(2023, 11, 6);//设置d1的日期
	d2.SetDate(2023, 11, 6);//设置d2的日期
	d1.Display();//打印d1的日期
	d2.Display();//打印d2的日期
	return 0;
}

在这里插入图片描述

上述Date类中有SetDate和Display两个成员函数,函数体中并没有关于不同对象的区分,那么当d1调用SetDate函数时,该函数是如何知道要设置的是d1对象,而不是d2对象呢?

C++中通过引入this指针解决该问题:C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问的。只不过所有操作对用户是透明的,即用户不需要来传递,而是编译器自动完成。

上述代码调用成员函数传参时,看似只传入了一些基本数据,实际上还传入了指向该对象的指针:
在这里插入图片描述
编译器进行编译时,看到的成员函数实际上也和我们所看到的不一样,每个成员函数的第一个形参实际上是一个隐含的this指针,该指针用于接收调用函数的对象的地址,用this指针就可以很好地访问到该对象中的成员变量:
在这里插入图片描述

this指针的特性

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

让我们通过下面这段代码更深入的理解this指针:

#include <iostream>
using namespace std;
class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
	}
	void Show()
	{
		cout << "Show()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	//p->Show();       //第一句代码
   //p->PrintA();     //第二句代码
}

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Flink 基础 -- 尝试Flink

官网 文档 v1.18.0 下载 数据流上的状态计算(Stateful Computations over Data Streams) Apache Flink是一个框架和分布式处理引擎&#xff0c;用于无界和有界数据流的有状态计算。Flink被设计成可以在所有常见的集群环境中运行&#xff0c;以内存中的速度和任何规模执行计…

实验(一):运算器实验

一、实验内容与目的 实验要求&#xff1a; 利用 CP226 实验仪的 K16..K23开关做为DBUS数据&#xff0c;其它开关做为控制信号&#xff0c;将数据写累加器A和工作寄存器W&#xff0c;并用开关控制ALU的运算方式&#xff0c;实现运算器的功能&#xff0c;将结果送入OUT寄存器。 实…

软件工程第十周

测试过程 单元测试 注意出错处理&#xff01;单元测试的数据处理部分请见Junit 单元测试之错误和异常处理-CSDN博客 单元测试准则 白盒&#xff1a;对系统结构非常清楚&#xff01;就像大题注重过程。 单元测试的测试环境 一定要保证整个环境是完整的&#xff0c;尽管可能没…

读写锁ReentrantReadWriteLock

读写锁ReentrantReadWriteLock是JDK1.5提供的一个工具锁&#xff0c;适用于读多写少的场景&#xff0c;将读写分离&#xff0c;从而提高并发性。读写锁允许的情况&#xff1a;一个资源可以被多个读操作访问&#xff0c;或者被一个写操作访问&#xff0c;但两者不能同时进行。 R…

IP地址会暴露我们的隐私吗?

IP地址在某种程度上可能会暴露个人或组织的隐私。以下是一些关于IP地址可能影响隐私的情况&#xff1a; 地理位置信息&#xff1a; IP地址的一部分信息是与地理位置相关的&#xff0c;因此可以用于确定用户或组织的大致地理位置。这可能泄露用户的身份或活动的地理背景。 互联…

Doris:Binlog Load导入数据

Binlog Load提供了一种使Doris增量同步用户在Mysql数据库的对数据更新操作的CDC(Change Data Capture)功能。Binlog Load需要依赖canal作为中间媒介&#xff0c;让canal伪造成一个从节点去获取Mysql主节点上的Binlog并解析&#xff0c;再由Doris去获取Canal上解析好的数据。 1…

centos k8s安装dapr

文章目录 安装helm更新helm库初始化dapr高可用方式安装 卸载dapr验证k8s的dapr安装rocketmq总结 安装helm 三个包放到一个目录下 chmod x get ./get helm version更新helm库 helm repo add dapr https://dapr.github.io/helm-charts/ helm repo update helm search repo dapr …

C/C++轻量级并发TCP服务器框架Zinx-游戏服务器开发004:游戏核心消息处理 - 玩家类的实现

文章目录 0 代码仓库1 需求2 AOI设计2.1 AOI算法简介2.2 AOI数据结构及实现2.2.1 玩家2.2.2 网格对象2.2.3 游戏世界矩形2.2.4 获取周围玩家的实现2.2.5 代码测试 2.3 GameRole结合AOI创建玩家2.3.1 创建游戏世界全局对象-GameRole继承AOIWorld的Player2.3.2 把玩家到游戏世界的…

Qt OpenMP使用

1、概念 OpenMP是一种用于共享内存并行系统的多线程程序设计方案&#xff0c;支持的编程语言包括C、C和Fortran。OpenMP提供了对并行算法的高层抽象描述&#xff0c;特别适合在多核CPU机器上的并行程序设计。编译器根据程序中添加的pragma指令&#xff0c;自动将程序并行处理&…

匿名类型与元组(ValueTuple)

匿名类型与元组&#xff08;ValueTuple&#xff09; 匿名类型 简介&#xff1a;匿名类型提供了一种方便的方法&#xff0c;可用来将一组相关的属性封装到单个对象中。匿名对象由编译器在编译时动态生成&#xff0c;它是只读的&#xff0c;且只在当前作用域中可见。它可以方便…

CDN加速技术:降低企业云服务成本的有效利用

在当今数字化时代&#xff0c;云服务已经成为企业运营的不可或缺的一部分。然而&#xff0c;与此同时&#xff0c;云服务的需求也在不断增长&#xff0c;使企业不得不应对更大的数据传输和负载。这就引出了一个关键问题&#xff1a;如何有效降低企业云服务成本&#xff0c;同时…

kubernetes-调度

目录 一、k8s调度简介 二、影响kubernetes调度的因素 1、nodename 2、nodeselector 3、亲和与反亲和 &#xff08;1&#xff09;nodeaffinity &#xff08;2&#xff09;podaffinity&#xff08;亲和&#xff09; &#xff08;3&#xff09;podantiaffinity&#xff0…

易点易动固定资产管理系统:提升固定资产领用效率的解决方案

在企业运营中&#xff0c;固定资产的领用和管理是一个重要的环节。然而&#xff0c;对于许多企业来说&#xff0c;固定资产领用的过程往往存在效率低下、信息不透明等问题。为了帮助企业提升固定资产领用效率并实现用量控制管理&#xff0c;我们引入了易点易动固定资产管理系统…

小知识:无源无线测温传感器可以安装在哪些部位?

无源无线测温传感器采用超低功耗设计&#xff1a;主芯片采用美国TI公司&#xff0c;功耗低&#xff0c;低可至0.03mw&#xff0c;区别于传统的感应供电&#xff0c;不存在发热现象。测温元件采用耐高温、高精度热敏电阻&#xff0c;测温范围宽至-40℃&#xff5e;200℃&#xf…

WebGL主要接口功能

WebGL&#xff08;Web Graphics Library&#xff09;提供了一组用于在Web浏览器中呈现3D和2D图形的接口类型和功能。下面是一些主要的WebGL接口类型和它们的功能&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交…

复盘一个诡异的Bug

该Bug的诡异之处在于这是一个由多种因素综合碰撞之后形成的综合体。纵观整个排查过程&#xff0c;一度被错误的目标误导&#xff0c;花费大量功夫后才找到问题点所在&#xff0c;成熟的组件在没有确凿证据之前不能随意怀疑其稳定性。 前言 此前在接入两台粒径谱仪&#xff08;…

tingpng 批量压缩工具

无聊的时候写的 自用 还行 https://ttkeji.lanzoul.com/iPCfY1e5wwwh

虹科示波器 | 汽车免拆检测 | 2017款路虎发现车行驶中发动机抖动且加速无力

一、故障现象 一辆2017款路虎发现车&#xff0c;搭载3.0L发动机&#xff0c;累计行驶里程约为3.8万km。车主反映&#xff0c;车辆在行驶过程中突然出现发动机抖动且加速无力的现象&#xff0c;于是请求拖车救援。 二、故障诊断 拖车到店后首先试车&#xff0c;发动机怠速轻微抖…

盈科视控荣获创响中国大赛第四名

近日&#xff0c;随着2023“创响中国”安徽省创新创业大赛省内赛区复赛的举办完成&#xff0c;60个项目从6个专项组中脱颖而出。 盈科视控凭借其【IC 载板及先进 PCB 智慧工厂服务商】参赛项目&#xff0c;荣获大赛第四名。 本次大赛由安徽省发改委、安徽省财政厅、合肥市人民…