【类和对象完结篇】

news2024/7/4 6:34:37

目录

❀初始化列表

构造函数体赋值

初始化列表

❀explicit关键字

❀static成员

什么是static成员?

特性

❀友元

友元函数

友元类

❀内部类

❀理解类和对象

🍀​​​​​​​​​​​​​​小结🍀


🎉博客主页:小智_x0___0x_

🎉欢迎关注:👍点赞🙌收藏✍️留言

🎉系列专栏:C++初阶

🎉代码仓库:小智的代码仓库

本节课重点:

  • 初始化列表
  • explicit关键字
  • static成员
  • 友元函数
  • 内部类
  • 理解类和对象

❀初始化列表

构造函数体赋值

当我们创建对象的时候,编译器可以通过调用构造函数,给对象中的各个成员变量一个初始值。

例如:

class Date {
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

但是上面构造函数调用了之后对象就会有一个初始值,但是它并不能称为函数的初始化,而是函数体内赋值,因为初始化只能初始化一次,而构造函数体可以多次及逆行赋值。
为了解决上面这样的问题,我们引入了初始化列表来初始化对象成员。

初始化列表

初始化列表:是以一个冒号开始,以逗号分隔数据成员列表,每个“成员变量”后面跟一个放在括号中的表达式或者初始值。
例如:

class Date {
public:
	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

 【注意】:

  1. 每个成员变量在初始化列表中最多只能出现一次(初始化只能初始化一次)。
  2. 类中包含以下成员,必须放在初始化列表的位置进行初始化:
    引用成员变量
    const成员变量
    自定义类型成员(且没有默认构造的时候)
    class A
    {
    public:
    	
    	A(int a)
    		:_a(a)
    	{
    		cout << "A(int a)" << endl;
    	}
    private:
    	int _a;
    };
    
    class B
    {
    public:
    	// 初始化列表:对象的成员定义的位置
    	B(int a, int& ref)
    		:_ref(ref)
    		, _n(1)
    		, _x(2)
    		, _aobj(a)
    	{
    		//_n = 0;
    		//_ref = ref;
    	}
    
    private:
    	// 声明
    	A _aobj;	  // 没有默认构造函数
    	// 特征:必须在定义的时候初始化
    	int& _ref;	  // 引用
    	const int _n; // const
    
    	int _x = 1;  // 这里1是缺省值,缺省值是给初始化列表的
    };

  3. 尽量的使用初始化列表初始化,因为不管是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表进行初始化。

    class Time
    {
    public:
    	Time(int hour = 0)
    		:_hour(hour)
    	{
    		cout << "Time()" << endl;
    	}
    private:
    	int _hour;
    };
    class Date
    {
    public:
    	Date(int day)
    	{}
    private:
    	int _day;
    	Time _t;
    };
    int main()
    {
    	Date d(1);
    }

    我们来看看代码执行过程:

    QQ录屏20230510173058

  4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,预期在初始化列表中的先后次序无关。

    class A
    {
    public:
    	A(int a)
    		:_a1(a)
    		, _a2(_a1)
    	{}
    
    	void Print() {
    		cout << _a1 << " " << _a2 << endl;
    	}
    private:
    	int _a2;
    	int _a1;
    };
    int main()
    {
    	A a(1);
    	a.Print();
    	return 0;
    }
    
    //A.输出1  1
    //B.程序崩溃
    //C.编译不通过
    //D.输出1  随机值

     我们可以看到我们明明是先给_a1(a),再给_a2(_a1)。但是初始化列表是根据声明顺序来初始化的,也就是说编译器先走的_a2(_a1),再走的_a1(a),所以才导致的这样的输出结果。

explicit关键字

我们平时创建对象的时候可以用下面这两种方式来创建>
 

class Date {
public:
	Date(int year, int month=1, int day=1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2020);

	Date d2 = 2023;
	return 0;
}

 之所以可以使用Date d2 = 2023;这种方式来创建对象是因为发生了隐式类型转换,整型类型(2023)转换成了自定义类型(Date)。
2023构造了一个Date的临时对象,临时对象再拷贝构造d2.但是编译器会优化为直接用2023构造。

如果我们想避免这种隐式类型转换我们可以在构造函数前面加上explicit关键字修饰。

❀static成员

什么是static成员?

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。

特性

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
  6. 静态成员函数可以调用非静态成员函数
  7. 非静态成员函数不可以调用类的静态成员函数

❀友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元分为:友元函数和友元类

友元函数

在我们实现Date类的时候会遇到这样的问题:
现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。

友元函数可以直接访问类的私有成员,它是定义在类外部普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

class Date
{
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;
	return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{
	_cin >> d._year;
	_cin >> d._month;
	_cin >> d._day;
	return _cin;
}
int main()
{
	Date d;
	cin >> d;
	cout << d << endl;
	return 0;
}

 【注意】:

  • ​​​​​​​友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

  • 友元关系是单向的,不具有交换性。
    比如Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  • 友元关系不能传递
    如果B是A的友元,C是B的友元,则不能说明C时A的友元。
  • 友元关系不能继承
class Time
{
	friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	void SetTimeOfDate(int hour, int minute, int second)
	{
		// 直接访问时间类私有的成员变量
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};

❀内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
【注意】:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中
的所有成员。但是外部类不是内部类的友元。
特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系。
class A
{
private:
	static int k;
	int h=10;
public:
	class B // B天生就是A的友元
	{
	public:
		void foo(const A& a)
		{
			cout << k << endl;//OK
			cout << a.h << endl;//OK
		}
	};
};
int A::k = 1;
int main()
{
	A::B b;
	b.foo(A());
	return 0;
}

❀​​​​​​​理解类和对象

现实生活中的实体计算机并不认识,计算机只认识二进制格式的数据。如果想要让计算机认识现实生活中的实体,用户必须通过某种面向对象的语言,对实体进行描述,然后通过编写程序,创建对象后计算机才可以认识。比如想要让计算机认识洗衣机,就需要:

  1.  用户先要对现实中洗衣机实体进行抽象---即在人为思想层面对洗衣机进行认识,洗衣机有什么属性,有那些功能,即对洗衣机进行抽象认知的一个过程
  2. 经过1之后,在人的头脑中已经对洗衣机有了一个清醒的认识,只不过此时计算机还不清楚,想要让计算机识别人想象中的洗衣机,就需要人通过某种面相对象的语言(比如:C++、Java、Python等)将洗衣机用类来进行描述,并输入到计算机中
  3. 经过2之后,在计算机中就有了一个洗衣机类,但是洗衣机类只是站在计算机的角度对洗衣机对象进行描述的,通过洗衣机类,可以实例化出一个个具体的洗衣机对象,此时计算机才能洗衣机是什么东西。
  4. 用户就可以借助计算机中洗衣机对象,来模拟现实中的洗衣机实体了。

在类和对象阶段,大家一定要体会到,类是对某一类实体(对象)来进行描述的,描述该对象具有那些属性,那些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化具体的对象。

🍀​​​​​​​​​​​​​​小结🍀

今天我们学习了初始化列表、explicit关键字、static成员、友元函数、内部类、理解类和对象相关的内容相信大家看完有一定的收获。

种一棵树的最好时间是十年前,其次是现在! 把握好当下,合理利用时间努力奋斗,相信大家一定会实现自己的目标!加油!创作不易,辛苦各位小伙伴们动动小手,三连一波💕💕~~~,本文中也有不足之处,欢迎各位随时私信点评指正! 

本节课代码已上传gitee仓库

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

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

相关文章

linux环境安装使用mysql详解

01-安装MySQL并启动 1.1 环境准备 # 1.卸载mariadb&#xff0c;否则安装mysql会出现冲突 &#xff08;1&#xff09;.执行命令rpm -qa | grep mariadb 会列出所有被安装的mariadb rpm 包&#xff1b; &#xff08;2&#xff09;.执行命令rpm -e --nodeps mariadb-libs-5.5.56…

super_排列组合lesson08易错题记录

此题用插空法解决&#xff1a;这个是组合的问题&#xff0c;总共10个学生&#xff0c;要分配到7个班级里&#xff0c;也就是要把这十个学生分为7部分&#xff0c;如果让学生们站在一起&#xff0c;就是在9个空位中插入6块木板&#xff0c;也就是C(9,6)也就是84 此题用捆绑法解决…

[Java进阶] 线程池详解

文章目录 前言1. 线程池的作用2. 线程池的应用3. 标准库中创建线程池的方式 前言 本文介绍线程池的作用和实现方法. 1. 线程池的作用 1.我们知道,线程的作用是由于进程的创建和销毁需要分配和回收资源,开销较大.而线程是"轻量级进程",创建销毁更高效. 2.线程池,比线…

汽车发动机点火性能测试仪设计

汽车发动机的点火系统包括上百种电气和机械零部件&#xff0c;生产线分布较广&#xff0c;因此分布式间接监控方式在点火系统的监测与故障诊断系统中得到广泛应用。发动机点火性能测试仪通过测量发动机的闭合角与分火角&#xff0c;对其分电器和点火器性能进行分析。 闭合角、分…

Python接口自动化测试实战系列

本节内容 接口及接口测试 网络基础知识&#xff1a;IP,域名, DNS及端口 网络基础知识&#xff1a;OSI七层模型及TCP协议 HTTP协议 接口及接口测试 这里插播一个段子 上图中&#xff0c;程序员口中提到的接口是什么意思呢&#xff1f; 手机壳有没有颜色这个属性&#xff0…

安全渗透工程师入门最快需要多久?提供具体路线和学习框架

前言 网络渗透这个东西学起来如果没有头绪和路线的话&#xff0c;是非常烧脑的。最快达到入门也要半年 理清网络渗透学习思路&#xff0c;把自己的学习方案和需要学习的点全部整理&#xff0c;你会发现突然渗透思路就有点眉目了。 网络安全好混&#xff0c;但不容易混得好。…

【顶配快速排序】CUTOFF配合三点中值法的三路划分

目录 1引入情境2 形式化描述2-1递归结构2-2 一次划分2-3 C实现 3 在工程中的改进3-1 处理重复元素双向划分三路划分C 实现 3-2 最差情况的改进三点中值法随机选择pivot短序列切回插入排序 4 全部改进技术加持 1引入情境 从低到高排成一队&#xff0c;怎么办&#xff1f; 以大雄…

RIME协议栈解读

// 新坑–contiki rime简介 rime类似于TCP/IP协议栈&#xff0c;属于分层结构。图片来自Adam Dunkels本人的rime论文介绍。 abc为anonymous broadcast&#xff0c;匿名广播。即将数据包通过无线射频驱动(radio driver)发出去&#xff0c;接收来自无线射频驱动所有的包并交给…

四月成功上岸阿里,年后准备了两个月,要个21k应该不过分吧~

先说下我基本情况&#xff0c;本科不是计算机专业&#xff0c;现在是学通信&#xff0c;然后做图像处理&#xff0c;可能面试官看我不是科班出身没有问太多计算机相关的问题&#xff0c;因为第一次找工作&#xff0c;阿里的游戏专场又是最早开始的&#xff0c;就投递了&#xf…

[JAVA数据结构]希尔排序/缩小增量法

前置内容&#xff1a;[JAVA]直接插入排序_HY_PIGIE的博客-CSDN博客 希尔排序&#xff0c;是将一个数组分成多组&#xff0c;在每一个组内进行排序。每进行一次排序&#xff0c;组中的元素都会增多&#xff0c;组数减少。 在组内进行直接插入排序 组数以/2的形式减少 例入&#…

离散Markov Chain序列及可视化

离散Markov Chain序列及可视化 文章目录 离散Markov Chain序列及可视化[toc]1 天气预测2 赌徒问题 1 天气预测 假设仅存在三种天气&#xff1a;晴天、阴天和雨天&#xff0c;每种天气状态构成的系统满足(齐次)马氏链过程&#xff0c;即下一期的天气状态仅取决于当前的天气状态…

网络安全是什么?如何成为一位优秀的网络安全工程师?

网络安全是什么&#xff1f; 首先说一下什么是网络安全&#xff1f; 网络安全工程师工作内容具体有哪些&#xff1f; 网络安全是确保网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然的或者恶意的原因而受到破坏、更改、泄露&#xff0c;系统连续可靠正常地…

idea部署tomcat(偏小白向)

目录 一、环境部署 1.安装idea ultimate任意版本 2.java稳定的版本如&#xff1a; 3.apache-tomcat任意版本&#xff0c;需要考虑兼容性&#xff0c;大家可以百度一下 二、部署简单的javaweb环境 总结 1.第一个问题 2.第二个问题 一、环境部署 1.安装idea ultimate任意版本…

Debian 11安装mysql 5.7.41

Debian 11安装mysql 5.7.41 1、下载mysql安装包2、安装文档2.1、安装依赖包2.2、安装MySQL包2.2.1、预设值数据库参数2.2.2、安装MySQL包 2.3、文件安装位置 3、使用mysql 5.7.41 数据库3.1、命令行登录MySQL 5.7.41 数据库3.2、navicat连接mysql 5.7.41 数据库3.2.1、修改mysq…

UWB技术开发的定位系统源码,高精度人员定位系统源码,室内定位系统源码人员定位/车辆定位/物品定位/材料定位

UWB技术定位系统源码&#xff0c;高精度人员定位系统源码&#xff0c;智慧工厂人员定位系统源码&#xff0c;室内定位系统源码 技术架构&#xff1a;单体服务 硬件&#xff08;UWB定位基站、卡牌&#xff09; 开发语言&#xff1a;java 开发工具&#xff1a;idea 、VS Code…

操作系统:12 线程竞争与线程池

1 基本概念 ① 竞争与同步 同一个进程中的线程能够共享进程中的绝大多数资源&#xff0c;当他们随意竞争时可能会导致共享资源被破坏、脏数据、不完整、不一致等问题 通过一些方法让进程中的线程在竞争资源时相互协调&#xff0c;避免出现以上问题&#xff0c;这种手段就称为线…

5月11日作业

思维导图 作业&#xff1a; 作业1&#xff1a; 作业2&#xff1a; 作业3&#xff1a; 作业4&#xff1a; 作业5&#xff1a;

算法设计与分析:枚举和递推的运用

目录 第1关&#xff1a;双关系递推数列 任务描述 相关知识 枚举算法的两种框架 递推算法的实施步骤 问题求解思路 编程要求 测试说明 第1关&#xff1a;双关系递推数列 任务描述 本关任务&#xff1a;运用枚举和递推的基本思想&#xff0c;通过编程计算出双关系递推数…

grafana + influxdb + telegraf构建linux性能监控平台

为了更好的做性能测试过程中监控服务器资源&#xff0c;提供可视化效果&#xff0c;下面介绍一种监控方案&#xff1a; grafana influxdb telegraf , 构建linux性能监控平台 安装3个软件 1.Grafana安装 grafana , 访问各类数据源 , 自定义报表、显示图表等等 , 用于提供界…

微星 B360M MORTAR电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板微星 B360M MORTAR 处理器英特尔 Core i5-9400 2.90GHz 六核已驱动 内存8 GB ( 金士顿 DDR4 2666MHz 8GB )已驱动 硬盘西数 WDS250G3X0C-00SJG0…