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

个人博客:代码菌@-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.mzph.cn/news/661250.shtml

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

相关文章

51单片机编程应用(C语言):数码管

目录 1.数码管原理 一位数码管引脚定义&#xff1a; 四位一体数码管&#xff1a; 多个数码管同时显示不同数字 51单片机的数码管的原理图 51单片机实现静态显示和动态显示 静态显示&#xff1a; 动态显示&#xff1a; 1.数码管原理 一位数码管引脚定义&#xff1a; 数码…

外包干了10个月,技术退步明显...

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

【代码随想录】LC 349. 两个数组的交集

文章目录 前言一、题目1、原题链接2、题目描述 二、解题报告1、思路分析2、时间复杂度3、代码详解 前言 本专栏文章为《代码随想录》书籍的刷题题解以及读书笔记&#xff0c;如有侵权&#xff0c;立即删除。 一、题目 1、原题链接 349. 两个数组的交集 2、题目描述 二、解题报…

C语言实战项目<贪吃蛇>

我们这篇会使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇 实现基本的功能&#xff1a; 结果如下: 1.一些Win32 API知识 本次实现呢我们会用到一些Win32 API的知识(WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口): 1)控制窗口大小 我们可以使用…

【Qt学习笔记】(二)信号和槽

信号和槽 1 信号和槽概述2 信号和槽的使用3 可视化生成槽函数4 自定义信号和槽5 带参数的信号和槽6 信号与槽的连接方式7 信号与槽的断开8 使用 Lambda 表达式来定义槽函数 1 信号和槽概述 在Qt中&#xff0c;用户和控件的每次交互过程称为一个事件。比如"用户点击按钮&q…

实时时钟芯片DS1307单片机C语言驱动程序

实时时钟RTC相关索引 1.单片机RTC及时钟芯片的时间到底从哪一年起始&#xff1f; 2.STM32F103单片机内部RTC实时时钟驱动程序 3.实时时钟芯片DS1302单片机C语言驱动程序 4.实时时钟芯片DS1307单片机C语言驱动程序 一、DS1307简介 DS1307是一款非易失性实时时钟&#xff08;R…

【Java程序设计】【C00209】基于SSM个人求职管理系统(论文+PPT)

基于SSM个人求职管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这个一个基于SSM的个人求职管理系统&#xff0c;本系统共分为三种权限&#xff1a;管理员、普通管理员、用户 管理员&#xff1a;首页、个人中心、用户管理、管理…

go并发编程-介绍与Goroutine使用

1. 并发介绍 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中的多个…

Go语言的100个错误使用场景(11-20)|项目组织和数据类型

前言 大家好&#xff0c;这里是白泽。 《Go语言的100个错误以及如何避免》 是最近朋友推荐我阅读的书籍&#xff0c;我初步浏览之后&#xff0c;大为惊喜。就像这书中第一章的标题说到的&#xff1a;“Go: Simple to learn but hard to master”&#xff0c;整本书通过分析100…

DevSecOps 参考模型介绍

目录 一、参考模型概述 1.1 概述 二、参考模型分类 2.1 DevOps 组织型模型 2.1.1 DevOps 关键特性 2.1.1.1 模型特性图 2.1.1.2 特性讲解 2.1.1.2.1 自动化 2.1.1.2.2 多边协作 2.1.1.2.3 持续集成 2.1.1.2.4 配置管理 2.1.2 DevOps 生命周期 2.1.2.1 研发过程划分…

leetcode刷题(剑指offer)54.螺旋矩阵

54.螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 输入&#xff1a;ma…

Java基础-集合框架

集合框架&#xff1a; 内存层面可考虑的数据存储容器&#xff1a;数组&#xff0c;集合 数组的特点&#xff1a;长度&#xff0c;存储元素类型确定&#xff0c;既可以放基本数据类型&#xff0c;也可以放引用数据类型 缺点&#xff1a;长度不可变&#xff0c;存储元素特点单…

从零开始 Linux(一):基础介绍与常用指令总结

从零开始 Linux 01. 概念理解 1.1 什么是 Linux&#xff1f; Linux 是一个开源免费的 操作系统&#xff0c;具有很好的稳定性、安全性&#xff0c;且有很强的处理高并发的能力 Linux 的应用场景&#xff1a; 可以在 Linux 下开发项目&#xff0c;比如 JavaEE、大数据、Python…

3D词云图

工具库 tagcanvas.min.js vue3&#xff08;框架其实无所谓&#xff0c;都可以&#xff09; 实现 <script setup> import { onMounted, ref } from vue; import ./tagcanvas.min.js;const updateFlag ref(false);// 词云图初始化 const initWordCloud () > {let …

RabbitMQ快速实战

目录 什么是消息队列&#xff1f; 消息队列的优势 应用解耦 异步提速 削峰填谷 总结 主流MQ产品特点比较 Rabbitmq快速上手 创建用户admin Exchange和Queue Connection和Channel RabbitMQ中的核心概念总结 什么是消息队列&#xff1f; MQ全称Message Queue&#xf…

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入) 反转(转移)控制(IOC Inverse of Control) 控制&#xff1a;对于成员变量赋值的控制权 反转控制&#xff1a;把对于成员变量赋值的控制权&#xff0c;从代码中反转(转移)到Spring⼯⼚和配置⽂件中完成好处&#xff1a;…

七、并发工具(上)

一、自定义线程池 1&#xff09;背景&#xff1a; 在 QPS 量比较高的情况下&#xff0c;我们不可能说所有的访问都创建一个线程执行&#xff0c;这会导致内存占用过高&#xff0c;甚至有可能出现 out of memory另外也要考虑 cpu 核数&#xff0c;如果请求超过了cpu核数&#…

【bitonicSort学习】

bitonicSort学习 什么是Bitonic Sort核心 什么是Bitonic Sort https://zhuanlan.zhihu.com/p/53963918 这个是用来并行排序的一个操作 之前学过一些CPU排序&#xff0c;快排 冒泡 归并啥的&#xff0c;有一些能转成并行&#xff0c;有一些不适合 像快排这种二分策略就可以考虑…

Vue3的自定义指令怎么迁移到nuxt3

一、找到Vue3中指令的源码 const DISTANCE 100; // 距离 const ANIMATIONTIME 500; // 500毫秒 let distance: number | null null,animationtime: number | null null; const map new WeakMap(); const ob new IntersectionObserver((entries) > {for (const entrie…

草图导入3d后模型贴材质的步骤?---模大狮模型网

3D模型在导入草图大师后出现混乱可能有多种原因&#xff0c;以下是一些可能的原因和解决方法&#xff1a; 模型尺寸问题&#xff1a;如果3D模型的尺寸在导入草图大师时与画布尺寸不匹配&#xff0c;可能导致模型混乱。解决方法是在3D建模软件中调整模型的尺寸&#xff0c;使其适…