C++学习——类和对象(三)

news2024/11/18 17:22:13

  接着我们就继续学习我们C++当中的相关的知识。

一:初始化列表

  还记得我们之前讲过的构造函数吗?我们在构造函数的函数体里面可以对对象当中的属性进行初始化。但是作为我们的构造函数来说,初始化的方式并不只是在构造函数体当中进行赋值。我们还可以构造函数列表当中进行对属性进行初始化。先举一个简单的例子:

#include<iostream>

//定义一个类,使用初始化列表进行初始化
class Date
{
public:
	Date(int year = 2022, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		//可以省略函数体当中的内容,直接在初始化列表当中初始化我们想要的内容
	}
	void print()
	{
		std::cout << _year << "年" << _month << "月" << _day << "日" << std::endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	//使用初始化列表初始化一个对象,检查初始化的效果
	Date d1(2023, 7, 22);
	d1.print();
	return 0;
}

 根据上面的例子当中,我们可以发现我们的构造函数当中的原本应该在函数体当中初始化的内容,我们却以一种奇奇怪怪的方式初始化出来。其实那种方式就是我们的初始化列表。我们在函数体之前先声明出要定义的对象。_year的部分表示我们类当中想要初始化的对象,后面括号里面的表示的是我们在形参当中传入的内容。并且初始化列表有一个要求,第一个初始化属性需要使用 : 进行引出,之后的都需要使用 , 进行分隔。观察初始化的结果:

  我们会发现我们使用初始化列表所初始化完成的对象和我们之前使用函数体初始化完成的得到的效果完全相同。那我们又为什么要重新定义出一个初始化列表初始化对象呢?

  这是因为,使用函数体初始化的内容并不是全部,有的几个成员变量必须使用初始化列表才可以初始化。我们就来一一举例。

  1.使用引用的成员变量

  我们之前说过引用并不能在初始化的时候定义一个空引用,也就是没有指向的对象。并且一旦定义完成之后就不能再继续进行修改。所以我们想要初始化起来就很麻烦,于是我们便有了初始化列表来解决这个问题,我们可以再初始化列表当中进行对引用的成员变量进行赋初值。

  使用函数体尝试初始化引用变量,我们会发现我们的编译器会报错:目标必须是初始化引用,无法编译完成。之后我们再通过初始化列表进行初始化引用对象:

   使用初始化列表进行初始化确实可以正常运行的。

  2.const成员变量

 使用函数体初始化会产生报错,所以使用初始化列表进行尝试:

  使用初始化列表可以正常的运行。

  3.自定义类型成员(且该类没有默认构造函数时)

 同样的我们先使用函数体初始化不具有默认参数的成员变量:

   我们会发现编译器依旧会产生报错,之后我们再来使用初始化列表进行初始化:
 

   上面三种成员变量我们只可以使用初始化列表进行初始化,这也是初始化列表产生的意义。在我们正常的程序编写的过程当中,我们比较推荐使用初始化列表进行初始化我们对象的成员变量,这是因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使 用初始化列表初始化。所以为了减少我们的区分,我们可以直接使用初始化列表进行初始化操作。

  还有一点极为重要的是:我们的初始化列表想要初始化成员变量,初始化的顺序是按照我们下方定义的私有的成员变量的顺序所进行的,所以假如我们想要使用之前定义好的变量继续初始化的时候就需要注意初始化顺序了,否则就会产生不必要的错误。

  就比如我们上面的代码所展示的一样,我们想要传一个参数同时初始化两个成员变量,所以我们先使用参数初始化了一个变量,之后使用初始化的变量又去初始化另一个变量,我们想要的到的预期的结果是两个 1 。但是我们实际得到的结果却是:
 

  就像我们上图所示的一个1一个随机值,但是为什么会出现这样的结果呢?这个时候就需要用到我们上面所说到的:其实我们初始化的顺序是按照我们在private当中定义的顺序来的。

   我们会发现我们先进行的a2初始化的时候是调用的a1,但是我们这个时候a1还没有进行初始化,我们得到的结果还是一个随机值。所以我们在之后打印的时候就会得到一个1,一个随机值的结果。所以我们在以后编写程序的时候需要养成良好的编写代码的习惯。需要按照下面定义的列表的顺序书写初始化列表,这个时候就可以避免上面的错误产生了。修正过的代码运行的结果:

   二:static修饰的成员变量

   介绍完初始化列表我们接下来就来介绍一下static修饰的成员变量。

  和我们C语言当中的使用方式是一样的,我们使用的static修饰的变量会被系统放在静态区,这个时候在调用完函数的时候我们的变量就不会被销毁,可以实现累加等操作。

  同样的在类当中也可以定义静态成员变量,需要注意的是我们使用static修饰的静态成员变量在初始化的时候一定得在类的外面,也就是全局的范围内定义,否则就会产生报错。

  如上面所示。为了解决我们上面产生的错误,我们需要将变量初始化到全局的范围内:
 

  静态成员变量还具有五大特性:

1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区

2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明

3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问

4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制 

所以当我们的类当中同时定义了静态成员函数和非静态成员函数的时候我们就需要仔细进行判断了,因为我们的静态成员函数是存放在静态区的,所以其中并不存在this指针,也正是因此,我们在调用的时候要想使用静态成员函数调用非静态成员函数就需要显示的传参使用,但是要是想要在非静态成员变量当中调用静态成员函数,那么我们就可以直接使用了。

  三:友元

  还记得我们之前使用到的友元函数吗?我们当时定义了一个全局范围内的函数,但是我们在函数当中又想调用我们类当中设立的私有的成员变量,在那个时候我们就是用到了友元。

  但是我们在使用友元函数的时候需要慎重,不能过多的使用友元函数,因为友元函数增加了我们程序之间的耦合度,(也叫做关联度,使得每一个函数和函数之间可以相互访问,违反了封装性的原则,所以要慎用)

  同样的我们也可以定义一个友元类,被设置成由友元类的对象我们同样可以访问其的私有成员变量。

#include<iostream>

//定义一个时间类
class Time
{
	friend class Date;
public:
	//定义一个构造函数
	Time(int hour = 10, int minute = 18, int second = 23)
	{
		_hour = hour;
		_minute = minute;
		_second = second;
	}
	void print()
	{
		std::cout << _hour << "时" << _minute << "分" << _second << "秒" << std::endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

//设置一个日期类,并将日期类设置成时间类的友元函数
class Date
{
private:
	int _year;
	int _month;
	int _day;
	Time _t;   //尝试在Date当中访问Time类的私有变量
public:
	//设置一个构造函数
	Date(int year = 2023, int month = 12, int day = 12)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//定义一个成员函数,用于设置并访问Time类
	void SetTime(int hour = 12, int minute = 12, int second = 12)
	{
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}
	void print()
	{
		std::cout << _year << "年" << _month << "月" << _day << "日" << std::endl;
		std::cout << _t._hour << "时" << _t._minute << "分" << _t._second << "秒" << std::endl;
	}
};
int main()
{
	//开始测试代码是否可以正常运行
	Date d(2022, 12, 12);
	d.SetTime(1, 1, 1);
	d.print();
	return 0;
}

  就像是上图中的那样,我们将Date类设置成为Time类的友元类,所以我们可以访问Time当中的私有变量。我们需要记住的是:我们frined友元函数的作用就像是一个特权,所以我们在设置友元函数的时候只需要记住,我们想要拥有特权访问其他的私有成员变量的类才需要设置成友元类。运行结果:

  和我们友元函数原理相同的还有我们的内部类。也就是说在一个类当中我们还可以设置另一个类,类似于一个嵌套的操作。内部类可以访问外部类的私有成员变量。我们可以将内部类看成是外部类的一个友元函数。代码如下:

#include<iostream>

//定义一个类,并在其中定义一个新的成员,作为其内部类
class Stu
{
private:
	char _name[20];
	int _age=12;
public:
	//定义一个内部类,尝试在其中访问外部类的私有成员变量
	class HomeWork
	{
	public:
		void ChangeAndFind(const Stu& s)
		{
			std::cout << s._age << std::endl;
		}
	};
};
int main()
{
	//使用一个HomeWork类,并访问其中的内容,并设置一个Stu类,用于传参
	Stu s1;
	Stu::HomeWork  hw1;
	hw1.ChangeAndFind(s1);
	
	return 0;
}

   我们需要注意的是:在访问内部类,并创建内部类的对象的时候,我们必须通过外部类的类名进行指定的使用才可以访问到我们的内部类。其他的在使用的时候一切正常。我们的内部类也可以成功的访问外部类的成员变量。运行结果如下:

                                                                                                                  ——类和对象 (完)

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

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

相关文章

Junit4+MultiThreadedTestRunner 并发测试

目录 前言&#xff1a; 具体步骤&#xff1a; 前言&#xff1a; 在进行软件测试时&#xff0c;我们需要确保应用程序在不同的并发情况下仍能正常运行。 最近要对一个类里的方法&#xff0c;进行压力测试。下面讲一下写出的 Junit4 的并发测试代码吧。如果要复用的话&#x…

通达信一看就懂的成交量指标公式_通达信公式

用法说明&#xff1a;黄色为立桩量&#xff0c;绿色长竖条为逃顶提示&#xff0c;蓝色与红箭头为突破&#xff0c;红色为牛&#xff0c;紫色为立桩三天法则成立&#xff0c;笑脸为寻底&#xff0c;棕色与绿箭头为破位&#xff0c;淡红色黑中线涨停&#xff0c;深绿色黑中线跌停…

yolov7裂缝检测

B站视频笔记。 1.首先到Github上找RoboFlow的仓库地址 该教程提供了传统算法比如Resnet、YOLO等&#xff0c;还有包含一些较新的算法。 2.通过Colab打开例程 可以直接通过Colab打开,还支持其他的打开方式&#xff0c;这里提供三种方式。 提示&#xff1a;点击授权即可。 …

dy设备deviceid iid注册分析

清楚缓存&#xff0c;重新打开app, 点击同意按钮&#xff0c;会触发设备注册&#xff1b; 很明显是一个post包&#xff0c;device_register 可以看到请求体加密了 那么 请求体是什么呢&#xff1f; 很老版本思路&#xff1a;都是直接明文注册 较老版本思路&#xff1a;在反编译…

二、SQL-5.DQL-8).案例练习

1、查询年龄为20,21,22,23岁的员工信息 select * from emp where age in(20, 21, 22, 23) and gender 女; 2、查询性别为男&#xff0c;并且年龄在20-40岁&#xff08;含&#xff09;以内的姓名为三个字的员工 select * from emp where gender 男 && age between 2…

如何从任何地方远程解决电脑问题?

​如何远程解决电脑问题&#xff1f; “嗨&#xff01;我有一台Windows 10家用电脑。我外出旅行&#xff0c;但我的家人告诉我我的电脑有一段时间无法正常工作。我该如何远程检查电脑并解决相应的问题&#xff1f;提前谢谢&#xff01;” 您是否正在寻找远程解决电…

重庆市北斗新型智慧城市政府项目

技术栈&#xff1a;使用vue2JavaScriptElementUIvuexaxiosmapboxcesium 项目描述&#xff1a;重庆市北斗新型智慧城市政府项目是基于千寻孪界开发的一款智慧城市项目&#xff0c;包含车辆实时位置定位&#xff0c;智能设备的报警&#xff0c;基础设施的部设等等功能 工作内容&a…

javascript 7种继承-- 寄生式继承分析(5)

文章目录 概要继承的进化史技术名词解释寄生式继承案列分析源代码解析效果图小结 概要 这阵子在整理JS的7种继承方式&#xff0c;发现很多文章跟视频&#xff0c;讲解后都不能让自己理解清晰&#xff0c;索性自己记录一下&#xff0c;希望个位发表需要修改的意见&#xff0c;共…

C++多线程编程(第一章 多线程基本使用)

C 11&#xff1b; C 14; C 17; C 20&#xff1b; 1、为什么要多线程 任务分解 耗时的操作&#xff0c;任务分解&#xff0c;实时响应 数据分解 充分利用多核CPU处理数据 数据流分解 读写分离&#xff0c;解耦合设计 2、相关代码 1、初步&#xff1a; join(),detach() …

【数学建模】时间序列分析

文章目录 1. 条件2. 模型分类3. SPSS处理时间序列 1. 条件 1.使用于具有时间、数值两种要素 2.数据具有周期性可以使用时间序列分解 2. 模型分类 叠加模型【YTSCI】 序列的季节波动变化越来越大&#xff0c;反映变动之间的关系发生变化乘积序列【YTSC*I】 时间序列波动保持恒…

JavaSwing+MySQL的学生选课系统

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88101629?spm1001.2014.3001.5503 Jdk&#xff1a;1.8 MySQL&#xff1a;5.7 功能&#xff1a;可以进行选课与查看学生基本资料 在这里插入图片描述

Jmeter GET 请求 参数为 Json 串且参数中存在变量的转化

目录 前言&#xff1a; 1.在 HTTP 请求下添加 BeanShell PreProcessor 前置处理器&#xff1a; 2.在 BeanShell PreProcessor 的实现&#xff1a; 3.在 HTTP 请求中的使用方式&#xff1a; 4.参数化的数据方式&#xff1a; 5.请求结果&#xff1a; 前言&#xff1a; 在 A…

网络流量监视器vnStat

什么是 vnStat &#xff1f; vnStat 是一个网络流量监视器&#xff0c;它使用内核提供的网络接口统计信息作为信息源。这意味着 vnStat 实际上不会嗅探任何流量&#xff0c;并且无论网络流量速率如何&#xff0c;都可以确保系统资源的轻度使用。 安装 在群晖上以 Docker 方式安…

Hive内部表和外部表

表类型详解 表分类 在Hive中,表类型主要分为两种 第一种&#xff1a;内部表 也叫管理表表目录会创建在集群上的{hive.metastore.warehouse.dir}下的相应的库对应的目录中。默认创建的表就是内部表 第二种&#xff1a;外部表 外部表需要使用关键字"external"&#xff…

勘探开发人工智能应用:地震层位解释

1 地震层位解释 层位解释是地震构造解释的重要内容&#xff0c;是根据目标层位的地震反射特征如振幅、相位、形态、连续性、特征组合等信息在地震数据体上进行追踪解释获得地震层位数据的方法。 1.1 地震信号、层位与断层 图1.1 所示为地震信号采集的过程&#xff0c;地面炮…

Sip网络音频对讲广播模块, sip网络寻呼话筒音频模块

Sip网络音频对讲广播模块&#xff0c; sip网络寻呼话筒音频模块 一、模块介绍 SV-2101VP和 SV-2103VP网络音频对讲广播模块 是一款通用的独立SIP音频功能模块&#xff0c;可以轻松地嵌入到OEM产品中。该模块对来自网络的SIP协议及RTP音频流进行编解码。 该模块支持多种网络协议…

ks webdid 滑块注册

web和app其实都一样&#xff0c;主要是针对于设备进行风控&#xff0c;web设备叫webdid; webdid注册出来&#xff0c;过了ks滑块激活&#xff0c;测试了主页&#xff0c;评论等接口都可以跑&#xff0c;平均也就2s注册一个&#xff0c;如果开并发那就更快了&#xff1b; 不过一…

React Native 0.72 版本,带来诸多更新

经过漫长的等待,React Native 终于迎来了0.72 版本,此处版本带来了Metro重要的功能更新、性能优化、开发人员体验的改进以及其他一些重要的变化。我们可以从下面的链接中获取此次版本更新的内容:0.72更新内容 一、Metro 新功能 众所周知,Metro 是 React Native 默认的 Jav…

图像处理之hough圆形检测

hough检测原理 点击图像处理之Hough变换检测直线查看 下面直接描述检测圆形的方法 基于Hough变换的圆形检测方法 对于一个半径为 r r r&#xff0c;圆心为 &#xff08; a , b &#xff09; &#xff08;a,b&#xff09; &#xff08;a,b&#xff09;的圆&#xff0c;我们将…

模拟量采集S_ITR函数(信捷C语言FC)

模拟量采集和转换函数非常简单,这里不再介绍,想了解具体算法的可以查看下面博客文章: PLC模拟量输入 模拟量转换FC S_ITR_博途模拟量转换程序_RXXW_Dor的博客-CSDN博客模拟量采集、工业现场应用特别广泛、大部分传感器的测量值和输出信号都是线型关系,所以我们可以利用线性…