【C++】类和对象(2)
目录
1. 初始化列表
2.explicit关键字
3. Static成员
3. 友元
3.1友元函数
3.2友元类
4. 内部类
5.匿名对象
1. 初始化列表
在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值,但是这个过程并不能称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值。因为初始化只能初始化一次,而构造函数体内可以多次赋值。
对象实例化是整体定义,对象的每个成员的定义和初始化则在初始化列表中完成
初始化列表:
以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式
//日期类
class Date
{
public://构造函数Date(int year, int month, int day):_year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
//栈类
class Stack
{
public://方法1:所以成员变量都使用初始化列表初始化Stack(int capacity = 4):_a((int*)malloc(sizeof(int)* capacity)),_capacity(capacity),_top(0){if (_a == nullptr){perror("malloc fail");exit(-1);}}//方法2:初始化列表+函数体内初始化Stack(int capacity = 4):_capacity(capacity),_top(0){_a = (int*)malloc(sizeof(int) * capacity);if (_a == nullptr){perror("malloc fail");exit(-1);}}
private:int* _a;int _capacity;int _top;
};
📖Note:
🐉每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
🐉类内包含以下成员,必须放在初始化列表位置进行初始化,不能在构造函数体内初始化
- 引用成员变量
- const成员变量
- 自定义类型成员(且该类没有默认构造函数的)
⑴对于const成员变量,在进入构造函数函数体内后,对const成员的操作是赋值操作,但是const成员变量不能被赋值修改,因此要在初始化列表进行初始化
⑵对于引用类型的变量,它在定义时必须初始化,且引用一旦引用一个实体,就不能引用其他实体,因此必须在初始化列表完成对引用变量的初始化

正确的初始化方式:
class A
{
public:A():_val(0),_n(10),_m(_val){cout << "调用构造函数A()" << endl;}
private:int _val;const int _n;//const成员int& _m;//引用类型变量
};

🐉尽量使用初始化列表进行初始化,因为不管是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化
对于自定义类型的成员变量,在为其初始化的时候会调用它的默认构造函数(无参构造函数,全缺省的构造函数,编译器自动生成的构造函数),当它的默认构造函数不存在时,编译器就会报错,为了避免默认构造不存在的这种情况,我们需要在初始化列表中对自定义类型成员变量初始化,如果在初始化列表显式定义了初始化,且自定义类型存在默认构造,最终的初始化结果是初始化列表的初始化结果。

🐉成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

2.explicit关键字
构造函数不仅可以构造和初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用
使用一个变量赋值给另一个不同类型的变量时,会发生隐式类型转换,但是这种转换不会改变原来变量,因为在赋值过程中,产生了一个临时变量拷贝原来变量的值,类型转换是对临时变量的操作

用explicit修饰函数,将会禁止构造函数的隐式转换.


用一个整型变量给日期类对象赋值,本来会先使用整型数据构造一个临时变量,再用临时变量给日期类对象赋值,即隐式的类型转换需要两步:构造+拷贝构造
但实际上实际编译器会进行优化,将隐式类型转换的 构造+拷贝构造 优化成 直接构造
因此以下代码可以通过编译:
const Date& d3 = 2022;
//临时变量具有常性,因此规范的写法应该加const修饰
Date d2 = 2023;
//编译器优化后直接构造,不产生临时变量,因此可以不加const

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

为什么类内的静态成员变量需要在类外定义初始化?
静态成员变量为所有类对象共享,不属于某个具体的对象,存放在静态区,所以不能在初始化列表初始化,静态成员变量必须在类外定义,定义时不添加static关键字 ,类中只是声明
📖Note:
- 类静态成员即可用:类名::静态成员 或者 对象.静态成员 访问
- 静态成员也是类的成员,受public、protected、private访问限定符的限制
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
- 静态成员函数可以不创建对象直接调用
🔹类的静态成员函数和静态成员变量配合使用


静态成员函数和非静态成员函数:
静态成员函数不可以调用非静态的成员函数
非静态的成员函数可以调用类的静态成员函数


问题:实现一个类,计算机程序中创建出了多少个类对象
方案:类对象都是构造和拷贝构造出来的,使用一个类内的静态成员变量,统计构造和拷贝构造的次数
对于一个类内的静态成员变量,其生命周期是全局的,但作用域受类域的限制
📖Note:
全局的静态变量,局部变量,类内的静态变量,它们的生命周期相同,都是全局的,区别是作用域不同

求累加和牛客网:求1+2+3+...+n_牛客题霸_牛客网

class Sum{
public://构造函数Sum(){_ret += _i;++_i;}static int GetRet(){return _ret;}
private:static int _i;static int _ret;
};
//静态成员变量的初始化
int Sum::_i = 1;
int Sum::_ret = 0;
class Solution {
public:int Sum_Solution(int n) {Sum arr[n];//创建一个大小为n的数组,即//需要创建n个对象,每个对象的创建都要调用构造函数初始化return Sum::GetRet();}
};
3. 友元
3.1友元函数
友元函数是将类外定义的函数在类内进行声明,让类外的函数也可以对类内的成员变量进行访问,如下例中流插入与流输出操作符的重载中需要使用友元函数

在类内重载流插入操作符时,程序报错原因:
类内成员函数的第一个参数默认是this指针(类类型),也就是二元操作符<<的左操作数,但实际上使用流插入操作符重载的第一个参数也就是左操作数应该是ostream类型的变量,这时即输出流对象和隐含的this指针在抢占第一个参数的位置,所以流插入操作符不能重载成成员函数,只能重载成全局函数,但又会导致类外没有办法访问成员,此时可以借助友元解决
🔷友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部进行声明,声明时加friend关键字
class Date
{//友元声明friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);
public://构造函数Date(int year = 1, 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 << endl;return _cout;
}
//流输出运算符重载
istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}
注意上面的代码在编写时,类的声明是写在运算符重载的前面,否则第二个参数就是未声明的符号,编译器报错
📖Note:
- 友元函数可以访问类的私有(private)和保护(protected)成员,但不是类的成员函数
- 友元函数不能使用const修饰(没有this指针)
- 友元函数可以在类定义的任何地方声明,不受访问限定符的限制
- 一个函数可以是多个类的友元函数
- 友元函数的调用和普通函数的调用原理相同
3.2友元类
友元类的声明如下:
//时间类
class Time
{//声明日期类为时间类的友元类,即在日期类中可以直接访问Time类中的私有成员变量friend class Date;
public://构造函数Time(int hour = 1){_hour = hour;cout << "调用构造函数Time()" << endl;}
private:int _hour;
};
//日期类
class Date
{
public://构造函数Date(int year = 1, int month = 1, int day = 1):_year(year),_month(month),_day(day){}//访问Time类中的成员变量void AccessTime(int hour){_t._hour = hour;}
private:int _year;int _month;int _day;Time _t;
};int main()
{Date d;d.AccessTime(12);//调用Date类中的成员函数,访问Time类中的成员变量return 0;
}

友元类的特性:
🔷友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员
比如上述的Time类和Date类,声明Date类是Time类的友元函数,即Date类中的所有成员函数都可以访问Time类中的私有成员变量

🔷友元关系是单向的,不具有交换性
比如上述的Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行

🔷友元关系不能传递
如果C是B的友元,B是A的友元,则不能说明C是A的友元
🔷友元关系不能继承
总结:
友元提供了一种突破封装的方式,为我们类外的函数访问类内成员变量提供了便利,但友元会增加耦合度,破坏了封装,因此应该合理使用。
4. 内部类
定义:如果一个类定义在另一个类的内部,这个类就叫做内部类。
📖Note:
- 内部类是一个独立的类,它不属于外部类 ,更不能通过外部类的对象去访问内部类的成员,外部类对内部类没有任何优先的访问权限
- 内部类就是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类中的所有成员,但是外部类不是内部类的友元
特性:
- 内部类可以定义在外部类的public、protected、private任意一个内
- 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象或类名
- sizeof(外部类)=外部类,和内部类没有关系

5.匿名对象
定义:对象定义时不用给对象取名字(类似匿名结构体)
对象定义的方法:
- 普通构造:A aa();
- 类型转换:A aa = 2;
- 匿名对象:A(); 或者 A(3);
📖Note:
一个匿名对象的生命周期只有它所在的这一行,下一行就会自动调用析构函数

相关文章:
【C++】类和对象(2)
目录 1. 初始化列表 2.explicit关键字 3. Static成员 3. 友元 3.1友元函数 3.2友元类 4. 内部类 5.匿名对象 1. 初始化列表 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值,但是这个过程并不能称为对对…...
用Python实现创建十二星座数据分析图表
下面小编提供的代码中,您已经将pie.render()注释掉,并使用了pie.render_to_file(十二星座.svg)来将饼状图渲染到一个名为十二星座.svg的文件中。这是一个正确的做法,如果您想在文件中保存图表而不是在浏览器中显示它。 成功创建图表…...
备战蓝桥杯————递归反转单链表的一部分
递归反转单链表已经明白了,递归反转单链表的一部分你知道怎么做吗? 一、反转链表Ⅱ 题目描述 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left < right 。请你反转从位置 left 到位置 right 的链表节点,返回 反…...
rabbitmq知识梳理
一.WorkQueues模型 Work queues,任务模型。简单来说就是让多个消费者绑定到一个队列,共同消费队列中的消息。 当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,…...
【数据结构与算法】动态规划法解题20240227
动态规划法 一、什么是动态规划二、动态规划的解题步骤三、509. 斐波那契数1、动规五部曲: 四、70. 爬楼梯1、动规五部曲: 五、746. 使用最小花费爬楼梯1、动规五部曲: 一、什么是动态规划 动态规划,英文:Dynamic Pro…...
备战蓝桥杯—— 双指针技巧巧答链表2
对于单链表相关的问题,双指针技巧是一种非常广泛且有效的解决方法。以下是一些常见问题以及使用双指针技巧解决: 合并两个有序链表: 使用两个指针分别指向两个链表的头部,逐一比较节点的值,将较小的节点链接到结果链表…...
半监督节点分类-graph learning
半监督节点分类相当于在一个图当中,用一部分节点的类别上已知的,有另外一部分节点的类别是未知的,目标是使用有标签的节点来推断没有标签的节点 注意 半监督节点分类属于直推式学习,直推式学习相当于出现新节点后,需要…...
软件文档-运维-开发-管理-资质-评审-招投标-验收
开发文档:这类文档主要用于记录软件的开发过程和细节,包括: 《功能要求》:描述了软件应具备的功能,是软件开发的基础。《投标方案》:向潜在的客户或招标方展示公司的技术和项目实施能力。《需求分析》&…...
猫头虎分享已解决Bug || Vue中的TypeError: Cannot read property ‘name‘ of undefined 错误
博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通鸿蒙》 …...
技术应用:使用Spring Boot、MyBatis Plus和Dynamic DataSource实现多数据源
引言 在现代的软件开发中,许多应用程序需要同时访问多个数据库。例如,一个电子商务平台可能需要访问多个数据库来存储用户信息、产品信息和订单信息等。在这种情况下,使用多数据源是一种常见的解决方案,它允许我们在一个应用程序…...
C# Onnx 使用onnxruntime部署实时视频帧插值
目录 介绍 效果 模型信息 项目 代码 下载 C# Onnx 使用onnxruntime部署实时视频帧插值 介绍 github地址:https://github.com/google-research/frame-interpolation FILM: Frame Interpolation for Large Motion, In ECCV 2022. The official Tensorflow 2…...
编程笔记 Golang基础 016 数据类型:数字类型
编程笔记 Golang基础 016 数据类型:数字类型 1. 整数类型(Integer Types)a) 固定长度整数:b) 变长整数: 2. 浮点数类型(Floating-Point Types)3. 复数类型(Complex Number Types&…...
一周学会Django5 Python Web开发-会话管理(CookiesSession)
锋哥原创的Python Web开发 Django5视频教程: 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计26条视频,包括:2024版 Django5 Python we…...
QT之QString.arg输出固定位数
问题描述 我需要用QString输出一个固定位数的数字字符串。起初我的代码是这样: int img_num 1 auto new_name QString("%1.png").arg((int)img_num, 3, 10, 0); //最后一个参数用u0也是一样的 qDebug() << "new_name:" << new…...
Linux下各种压缩包的压缩与解压
tar 归档,不压缩,常见后缀 .tar # 将文件夹归档成为一个包 tar cf rootfs.tar rootfs # 将归档包还原为文件夹 tar xf rootfs.tar # 将归档包还原到路径 a/b/c tar xf rootfs.tar -C a/b/cgzip压缩, 常见后缀 .tar.gz .tgz # 压缩 tar czf …...
【ctfshow—web】——信息搜集篇1(web1~20详解)
ctfshow—web题解 web1web2web3web4web5web6web7web8web9web10web11web12web13web14web15web16web17web18web19web20 web1 题目提示 开发注释未及时删除 那就找开发注释咯,可以用F12来查看,也可以CtrlU直接查看源代码呢 就拿到flag了 web2 题目提示 j…...
GEE入门篇|遥感专业术语(实践操作4):光谱分辨率(Spectral Resolution)
目录 光谱分辨率(Spectral Resolution) 1.MODIS 2.EO-1 光谱分辨率(Spectral Resolution) 光谱分辨率是指传感器进行测量的光谱带的数量和宽度。 您可以将光谱带的宽度视为每个波段的波长间隔,在多个波段测量辐射亮…...
c++中模板的注意事项
1. 模板定义时,<>中的虚拟类型参数不能为空。(因为我们使用模板就是希望使用模拟类型代替其它的类型,如果我们不定义就没有意义了) 2. 无论是定义函数模板还是类模板,其实template定义与后面使用虚拟类型的类或者函数,是…...
【代码随想录python笔记整理】第十三课 · 链表的基础操作 1
前言:本笔记仅仅只是对内容的整理和自行消化,并不是完整内容,如有侵权,联系立删。 一、链表 在之前的学习中,我们接触到了字符串和数组(列表)这两种结构,它们具有着以下的共同点:1、元素按照一定的顺序来排列。2、可以通过索引来访问数组中的元素和字符串中的字符。由此,…...
JAVA工程师面试专题-《Mysql》篇
目录 一、基础 1、mysql可以使用多少列创建索引? 2、mysql常用的存储引擎有哪些 3、MySQL 存储引擎,两者区别 4、mysql默认的隔离级别 5、数据库三范式 6、drop、delete 与 truncate 区别? 7、IN与EXISTS的区别 二、索引 1、索引及索…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
