【C++杂货铺】详解类和对象 [下]

news2024/11/27 16:25:43

个人博客:代码菌@-CSDN博客

专栏:C++杂货铺_代码菌@的博客-CSDN博客


目录

🌈前言🌈

📁 初始化列表(灰常重要)

 📂 引入

  📂 概念

   📂  特性

📁 拓展构造函数 —— explicit关键字

📁 static成员

 📂 概念

📂 特性

📁 友元

 📂 友元函数

 📂 友元类

📁 内部类(了解)

 📂概念

 📂特性

📁 匿名对象

📁 总结


🌈前言🌈

        欢迎收看本期【C++杂货铺】,这期内容,我们将围绕C++中类和对象部分内容进行讲解,包含了 初始化列表,static成员,友元等内容。

        下面内容是上两期的内容,如果想要回顾,可以点击链接。

【C++杂货铺】详解类和对象 [上]-CSDN博客

【C++杂货铺】详解类和对象 [中]-CSDN博客

📁 初始化列表(灰常重要)

 📂 引入

       在 【C++杂货铺】详解类和对象 [中]-CSDN博客中,我们讲解了什么是构造函数,构造函数是将成员变量赋初值的,在创建类的对象时必须调用的默认成员函数。

        在这里大家可能以为,构造函数就是初始化,其实不然,构造函数只是赋初值。不是初始化,初始化有一个特点,就是定义时赋值,只能初始化一次。

class Date
{
public:
    Date(int year = 1, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
        _year = 1;    //构造函数中,能赋多次值
    }
private:
    int _year;
    int _month;
    int _day;
};

        所以,构造函数不是成员变量定义初始化的地方,那哪里是呢?这就是初始化列表。

  📂 概念

        以 : 开始,接着是一个逗号分割的数据成员列表,每个“成员变量”后面跟一个放在 ( ) 中的初始值或表达式。

        初始化列表就是每个成员变量定义初始化的位置。  

class Date
{
public:
    //初始化列表。
    Date(int year = 1, int month = 1, int day = 1)
      :_year(year)
      ,_month(month)
      ,_day(day)
    {
      //{}内为构造函数,执行完初始化列表后,执行构造函数
    }
private:
    int _year;
    int _month;
    int _day;
};

   📂  特性

        1. 每个成员变量能在初始化列表中执行一次。(初始哈只能进行一次)

        2. 类中包含一下成员时,必须放在初始化列表位置进行初始化。

                i. 引用成员变量 。引用必须初始化,类中初始化位置是初始化列表。

               ii. const修饰的成员变量。const修饰的变量的值只能定义初始化时修改,之后不能修改。

              iii. 自定义类型对象,且没有默认构造函数。类对象初始化必须调用构造函数初始化,有默认构造函数编译器自动调用默认构造函数。

class A
{
public:
     A(int a)
     :_a(a)
     {}
private:
     int _a;
};
class B
{
public:
     B(int a, int ref)
     :_aobj(a)
     ,_ref(ref)
     ,_n(10)
     {}
private:
    A _aobj;  // 没有默认构造函数
    int& _ref;  // 引用
    const int _n; // const 
};

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

        4. 成员变量在类中的声明顺序初始化列表中的初始化顺序

📁 拓展构造函数 —— explicit关键字

        构造函数不仅可以构造与初始化对象,对于单个参数或者多参数的构造函数,还具有类型转换的作用

1. 单参数的隐式类型转换。

//没有使用explicit修饰,具有类型转换作用
Date(int year)
:_year(year)
{}
    
    // explicit修饰构造函数,禁止类型转换
explicit Date(int year)
:_year=year;
{}


// 用一个整形变量给日期类型对象赋值
// 实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值
Date d1 = 2023;

2. 多参数的隐式类型转换。

//没有使用explicit修饰,具有类型转换作用 
Date(int year, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}

//使用explicit修饰,不具有类型转换作用
 explicit  Date(int year, int month = 1, int day = 1)
 : _year(year)
 , _month(month)
 , _day(day)
 {}

Date d1 = 2024;

📁 static成员

 📂 概念

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

class A
{
public:
    A()     //默认构造函数
    { 
        ++_scount; 
    }
    A(const A& t)     //拷贝构造函数
    {
        ++_scount; 
    }    
    ~A()             //析构函数
    {
        --_scount; 
    }
    static int GetACount()     //静态成员函数
    {
         return _scount; 
    }
private:
    static int _scount;       //静态成员变量
};

int A::_scount = 0;    //静态成员变量初始化

📂 特性

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

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

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

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

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

📁 友元

        在【C++杂货铺】详解类和对象 [上]-CSDN博客 中,我们简单了了解了一下什么是封装和访问限定符,即通过访问限定符,完成封装,用户取不到类的成员变量。

        但是友元提供了一种突破封装的方式,提供了遍历,外部用户可以取到内部的成员变量。但是增加了耦合性,破坏了封装,所以友元不宜多用。

 📂 友元函数

        例如,我们尝试在类中重载operator<<,然而发现没法讲其重载,因为cout的输出流对象在隐含的this指针之前,this指针默认是一个第一个参数,然而实际上cout是一个参数。

        所以不能在类中重载,只能将其重载成去哪聚函数,但有导致受访问限定符限制不能访问内部成员变量,此时,就需要友元。>>同理。

1. 如果在类中定义,调用时必须写成 对象<<cout 。所以不建议在类中重载。

clas Date
{
public:
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
	// 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
	ostream & operator<<(ostream& _cout)
	{
		_cout << _year << "-" << _month << "-" << _day << endl;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};

2. 重载为全局函数。

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;
}

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

        1. 友元函数可以访问类的私有和保护函数,但不是类的成员函数

        2. 友元函数不能用const修饰。

        3. 友元函数可以在类定义的任何地方声明,不受访问限定符限制

        4. 一个函数可以是多个类的友元函数

        5. 友元函数的调用与普通函数的调用原理同理

 📂 友元类

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

class Time
{
	friend class Date;
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. 友元关系是单向的,不具有交换性。

        比如Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。

2. 友元关系不能传递。

        如果C B 的友元, B A 的友元,则不能说明 C A 的友元。
3. 友元关系不能继承。

📁 内部类(了解)

 📂概念

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

 📂特性

        1. 内部类可以定义在外部类的 public protected private 都是可以的。
        2. 注意内部类可以直接访问外部类中的 static 成员,不需要外部类的对象 / 类名。
        3. sizeof(外部类 )= 外部类,和内部类没有任何关系。

📁 匿名对象

        有时,我们只想要超看特定状态下,类的成员函数的情况,此时可以使用匿名对象来调用成员函数。

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
class Solution {
public:
	int Sum_Solution(int n) {
		//...
		return n;
	}
};
int main()
{
	// A aa1(); 不能这么定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义
	
    // 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,
	// 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数
	A();
	A aa2(2);
	// 匿名对象在这样场景下就很好用。
	Solution().Sum_Solution(10);
	return 0;
}

📁 总结

        总结,本期内容讲解了类的成员变量在构造函数赋初值,在初始化列表定义和初始化。此外,拓展了构造函数的隐式类型转换,编译器自动将数据转换成类 类型。我们可以通过友元函数来访问类的内部成员。了解了什么是内部类和匿名对象。

        本期【C++杂货铺】的内容就结束了,类和对象也全部讲解完毕。

        如果感觉本期内容对你有所帮助,欢迎点赞,收藏,关注。Thanks♪(・ω・)ノ

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

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

相关文章

【计算机二级考试C语言】C递归

目录 C 递归 数的阶乘 实例 斐波那契数列 实例 C 递归 递归指的是在函数的定义中使用函数自身的方法。 举个例子&#xff1a; 从前有座山&#xff0c;山里有座庙&#xff0c;庙里有个老和尚&#xff0c;正在给小和尚讲故事呢&#xff01;故事是什么呢&#xff1f;"从…

关闭idea之后,项目还在运行,端口被占用

今天在写项目的时候&#xff0c;中途安装了一个插件&#xff0c;而且插件显示需要重启idea&#xff0c;重启的时候项目正在运行&#xff0c;重启之后发现idea没有显示有项目正在运行&#xff0c;当我要开启项目的时候&#xff0c;发现无法开启&#xff0c;显示端口被占用了&…

您企业的(AI)人工智能处于哪个准备阶段?

全新AI准备度评估工具现已推出 根据Gartner 2020年CIO调查报告&#xff0c;仅19%的首席信息官声称其AI项目已投产。这意味着&#xff0c;如果要将AI计划部署到生产过程中&#xff0c;高达80%的企业无法实现。我们发现&#xff0c;澳鹏客户取得成功的几率要高出三倍&#xff0c…

@Test Annotation属性- dependsOnMethods属性

目录 语法 如果test1&#xff08;&#xff09;失败了怎么办&#xff1f;test2&#xff08;&#xff09;测试会发生什么&#xff0c;因为它依赖于test1&#xff1f; 如果我们在test1&#xff08;&#xff09;方法上不使用Test注释&#xff0c;但在test 2&#xff08;&#xf…

放弃Nacos作为配置中心,转而选择这款神器~

目前&#xff0c;我们所有微服务的配置中心都没有采用Nacos&#xff0c;而是选择了另一款携程开源的分布式配置中心Apollo&#xff0c;今天就跟大家详细介绍一下这款神级配置中心 1. 基本概念 由于 Apollo 概念比较多&#xff0c;刚开始使用比较复杂&#xff0c;最好先过一遍…

YOLOv5改进系列(29)——添加DilateFormer(MSDA)注意力机制(中科院一区顶刊|即插即用的多尺度全局注意力机制)

【YOLOv5改进系列】前期回顾&#xff1a; YOLOv5改进系列&#xff08;0&#xff09;——重要性能指标与训练结果评价及分析 YOLOv5改进系列&#xff08;1&#xff09;——添加SE注意力机制 YOLOv5改进系列&#xff08;2&#xff09;——添加CBAM注意力机制 YOLOv5改进系列&…

【Java 数据结构】栈和队列

栈和队列 1. 栈(Stack)1.1 概念1.2 栈的使用1.3 栈的模拟实现1.4 栈的应用场景1.5 概念区分 2. 队列(Queue)2.1 概念2.2 队列的使用2.3 队列模拟实现2.4 循环队列 3. 双端队列 (Deque)4. 面试题 1. 栈(Stack) 1.1 概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在…

STM32入门教程-2023版【5-1】NVIC

关注 点赞 不错过精彩内容 大家好&#xff0c;我是硬核王同学&#xff0c;最近在做免费的嵌入式知识分享&#xff0c;帮助对嵌入式感兴趣的同学学习嵌入式、做项目、找工作! 四、NVIC &#xff08;1&#xff09;NVIC基本结构 外部中断的整体结构图如下&#xff1a; 这个NVI…

代码随想录算法训练营29期|day37 任务以及具体任务

第八章 贪心算法 part06 738.单调递增的数字 版本2 class Solution {public int monotoneIncreasingDigits(int n) {String s String.valueOf(n);char[] chars s.toCharArray();int start s.length();for (int i s.length() - 2; i > 0; i--) {if (chars[i] > chars…

利用ASM功能实现零停机oracle RAC存储迁移

在实际生产过程中&#xff0c;经常会遇到比如新旧存储替换等场景&#xff0c;如果是一般情况可能只有做数据迁移才能实现&#xff0c;而迁移可能就存在停机的可能 这里介绍利用ASM DG加盘踢盘功能实现零停机存储迁移&#xff1b;原理很简单 将新存储磁盘添加到data dg&#xf…

江科大stm32学习笔记9——OLED调试工具

一、OLED OLED&#xff1a;有机发光二极管&#xff0c;供电3~5.5V&#xff0c;0.96寸OLED通信协议&#xff1a;I2C/SPI&#xff0c;分辨率&#xff1a;128*64 二、调试方式 串口调试&#xff1a;通过串口通信&#xff0c;将调试信息发送到电脑端&#xff0c;电脑使用串口助手…

Mysql数据库锁--全局锁、表锁、行锁

Mysql数据库按照加锁范围划分 根据加锁的范围&#xff0c;MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类 全局锁 全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法&#xff0c;命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只…

CTF盲水印工具:Blind-WaterMark安装

工具下载地址&#xff1a;GitCode - 开发者的代码家园 下载完毕后&#xff0c;只留这些东西就行 接下来需要安装两个依赖&#xff1a; opencv、matplotlib 直接pip install安装的话&#xff0c;工具使用会报错 所以需要到网站里挑选适合的版本进行安装 下载地址&#xff1…

四通道 LVDS 差分线缆接收器MS21148T

产品简述 MS21148T 是一款四路低压差分信号 (LVDS) 线路接收器。在 输入共模电压范围内&#xff0c;每一路差分接收器都可以把 100mV 的差 分输入电压转换成有效的逻辑输出。 该芯片可应用于约 100Ω 的 受控阻抗介质上进行点对点基带数据传输。传输介质可以是印 刷电…

基于 Langchain-Chatchat,我搭建了一个本地知识库问答系统

文章目录 一、LangChain-Chatchat二、搭建步骤2.1 环境配置2.2 模型下载2.3 初始化知识库和配置文件2.4 一键启动2.5 启动界面示例 技术交流群用通俗易懂方式讲解系列 一、LangChain-Chatchat 基于 ChatGLM 等大语言模型与 Langchain 等应用框架实现&#xff0c;开源、可离线部…

图像异或加密、解密的实现

很多论文提到了从左上角开始做异或,逐行推导得到结果。 解密过程是加密的逆过程。 先看其基本方法: 参考文献: A Chaotic System Based Image Encryption Scheme with Identical Encryption and Decryption Algorithm 大多数论文都用了这个思路,我们使用MATLAB实现代码…

永久删除 Elasticsearch 中的主节点

Elasticsearch 是一个开源分布式搜索和分析引擎&#xff0c;用于各种任务&#xff0c;例如全文搜索、日志分析和实时数据分析。 Elasticsearch 集群由一个或多个节点组成&#xff0c;每个节点可以具有多种角色&#xff0c;包括主节点&#xff08;master node&#xff09;、数据…

【JaveWeb教程】(37)SpringBootWeb案例之《智能学习辅助系统》的详细实现步骤与代码示例(10)JWT令牌技术讲解

目录 SpringBootWeb案例10 JWT令牌2.3 JWT令牌2.3.1 介绍2.3.2 生成和校验2.3.3 登录下发令牌 SpringBootWeb案例10 JWT令牌 2.3 JWT令牌 前面我们介绍了基于令牌技术来实现会话追踪。这里所提到的令牌就是用户身份的标识&#xff0c;其本质就是一个字符串。令牌的形式有很多…

【vim 学习系列文章 3.2 -- vim 删除 空格】

文章目录 vim 删除行尾空格 vim 删除行尾空格 在代码开发的过程中&#xff0c;经常会遇到行尾有空格的现象&#xff0c;如下&#xff1a; 我们可以在 .vimrc 中通过map 命令来映射删除行尾空格的快捷键&#xff0c;如下&#xff1a; map d<space> :%s/\s*$//g <cr…

C++初阶 类和对象(补充)

目录 一、友元 1.1什么是友元&#xff1f; 1.2如何使用友元&#xff1f; 1.3使用友元 1.4使用友元注意事项 二、初始化列表 2.1什么是初始化列表? 2.2为什么要有初始化列表&#xff1f; 2.3使用初始化列表 2.4注意事项 一、友元 1.1什么是友元&#xff1f; 友元是一…