【C++】类与对象(四)——初始化列表|explicit关键字|static成员|友元|匿名对象
前言:
初始化列表,explicit关键字,static成员,友元,匿名对象
文章目录
- 一、构造函数的初始化列表
- 1.1 构造函数体内赋值
- 1.2 初始化列表
- 二、explicit关键字
- 三、static成员
- 四、友元
- 4.1 友元函数
- 4.2 友元类
- 五、内部类
- 六、匿名对象
一、构造函数的初始化列表
1.1 构造函数体内赋值
class Date{
public:Date(int year, int month, int day){//赋值,并非初始化_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
构造函数调用之后,在函数体中给成员变量赋值,但这并不能称为初始化,因为初始化是在变量或对象的创建时进行的,如果有初始化,那么仅有一次只有一次,而构造函数体内可以多次赋值。
对于某些类型的成员变量,必须进行初始化。函数体内并不能满足这些类型的成员变量进行初始化,因此有了初始化列表的概念。
1.2 初始化列表
初始化列表用于在构造函数中初始化类成员变量的语法结构:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
_year
_month
_day
被year,month,day进行初始化
Date(int year, int month, int day) :_year(year), _month(month), _day(day) {//函数体内其他操作
}
-
实际上,即使没有显式写出初始化列表,成员变量依然会走初始化列表,但是因为没有初始值,因此成员变量是默认值。且初始化列表的顺序是成员变量声明的顺序。
-
以下成员,必须放在初始化列表位置进行初始化
- 引用成员变量
- const成员变量
- 自定义类型成员(且该类没有默认构造函数时)
class A{ public:A(int a):_a(a){} private:int _a; };class B{ private:A _aobj; // 自定义类型且没有默认构造函数int& _ref; // 引用const int _n; // const public:// _aobj(a)可以理解为调用A类的构造函数B(int a, int ref):_aobj(a), _ref(ref), _n(0){// 其他操作} };int main() { B b(10,5);return 0; }
-
成员变量声明时提供缺值
当成员变量没有在初始化列表初始化时,成员变量被默认初始化为缺省值。class Date{ public:Date(int year, int month, int day) :_month(month),_day(day) {//函数体内其他操作} private:int _year = 1;int _month;int _day; };int main() {//B b();Date d(2024, 1, 31);return 0; }
通常初始化列表与构造函数体内赋值混合使用。
二、explicit关键字
-
单参数构造函数可以支持隐式类型的转换。
意思是允许通过给定类型的单一参数将对象从一种类型转换为另一种类型,而无需显式调用构造函数。class Distance { private:double meters;public:// 单参数构造函数,允许从 double 类型隐式转换为 Distance 类型Distance(double m) : meters(m) {} };int main() {// 隐式类型转换:double 到 DistanceDistance d1 = 10.5;// 显式类型转换也是可行的Distance d2 = Distance(15.2);return 0; }
在这个例子中,
Distance
类具有一个单参数构造函数,允许将double
类型的值隐式转换为Distance
类型。当我们使用Distance d1 = 10.5;
时,编译器会自动调用单参数构造函数,将10.5
隐式转换为Distance
类型的对象d1
。 -
C++11及之后的标准中,引入了一种新的特性,即“允许多参数的构造函数用于隐式类型转换”
例如:
class MyClass { public:// 多参数的构造函数MyClass(int x, double y) {// 构造函数逻辑std::cout << "Constructing MyClass with parameters: " << x << ", " << y << std::endl;} };int main() {// 隐式类型转换,调用构造函数MyClass obj = {42, 3.14};return 0; }
在这个例子中,
MyClass
类具有一个接受两个参数的构造函数。使用初始化列表{42, 3.14}
进行对象的初始化时,实际上发生了隐式类型转换,将两个参数传递给构造函数。 -
当一个构造函数被 explicit 修饰时,它禁止隐式类型转换,只允许显式调用。
explicit Distance(double m) : meters(m) {}
// 隐式类型转换会引发编译错误 Distance d1 = 10.5; // 错误// 必须使用显式类型转换 Distance d2 = Distance(15.2); // 正确
三、static成员
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用
static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化
-
静态数据成员: 静态数据成员是属于类而不是类的对象的成员变量。所有类的对象共享相同的静态数据成员。
class MyClass { public:// 构造函数,用于增加 countMyClass() {count++;}int& GetCount() {return count;} private:// 静态数据成员static int count; };// 初始化静态数据成员 int MyClass::count = 0;int main() {// 创建对象,增加 countMyClass obj1;MyClass obj2;// 访问静态数据成员std::cout << "Count: " << obj1.GetCount() << std::endl;std::cout << "Count: " << obj2.GetCount() << std::endl;return 0; }
-
静态成员函数: 静态成员函数是不依赖于类的实例而存在的函数。它没有访问类的非静态成员,因为它不通过实例来调用,而是通过类名和范围解析运算符
::
来调用。class MathOperations { public:// 静态成员函数,用于加法运算static int add(int a, int b) {return a + b;} };int main() {// 调用静态成员函数int result = MathOperations::add(3, 5);std::cout << "Result: " << result << std::endl;return 0; }
特性总结
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
- 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
- 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
- 静态成员也是类的成员,受
public
、protected
、private
访问限定符的限制
静态成员函数可以调用非静态成员函数吗?
非静态成员函数可以调用类的静态成员函数吗?
静态成员函数可以调用非静态成员函数,但非静态成员函数不能直接调用类的静态成员函数。这是因为静态成员函数在调用时没有实例上下文,而非静态成员函数必须通过实例来调用。
四、友元
友元(Friend)可以用来解决类的封装性和访问控制方面的一些限制。友元可以是函数、类或者整个类中的函数。友元的存在允许特定的外部实体访问类的私有或受保护成员。
4.1 友元函数
友元函数:使用
friend
关键字声明一个非成员函数,允许该非成员函数访问该类的私有成员。
下面是一个简单的示例:
友元函数的声明通常放在类的声明中,友元函数的定义放在类的外部。
class MyClass {
private:int privateData;public:MyClass(int data) : privateData(data) {}// 声明友元函数friend void displayPrivateData(const MyClass&);
};// 定义友元函数
void displayPrivateData(const MyClass& obj) {std::cout << "Private data: " << obj.privateData << std::endl;
}int main() {MyClass obj(42);displayPrivateData(obj); // 友元函数可以访问私有成员return 0;
}
displayPrivateData
函数被声明为 MyClass
的友元函数,因此它可以访问 MyClass
中的私有成员 privateData
。在 main
函数中,我们可以直接调用 displayPrivateData
函数来显示 obj
对象的私有成员数据。
需要注意的是,友元函数不是类的成员函数,因此它们不能使用成员访问运算符 .
或 ->
来访问私有成员,而是需要通过参数传递对象来访问。
4.2 友元类
友元类:将一个类将另一个类声明为友元,从而允许友元类访问该类的私有成员和受保护成员。
举例:
class MyClass {
private:int privateMember;// 将 FriendClass 声明为友元类friend class FriendClass;public:MyClass(int data) : privateMember(data) {}
};class FriendClass {
public:void accessPrivateMember(const MyClass& obj) {// 友元类可以访问 MyClass 的私有成员int data = obj.privateMember;}
};int main() {MyClass a(10);FriendClass b;b.accessPrivateMember(a);return 0;
}
在这个例子中,FriendClass
被声明为 MyClass
的友元类。因此,FriendClass
的成员函数 accessPrivateMember
可以访问 MyClass
中的私有成员 privateMember
。
友元类的存在使得特定的类能够共享私有成员,这在某些情况下可能很有用,但同时也可能破坏了封装性。因此,在使用友元类时需要权衡利弊,并确保其使用符合设计原则和需要。
五、内部类
内部类定义在另一个类内部的类,可以直接访问外部类的私有成员,而不需要通过对象来实现。
下面是一个简单的示例:
class Outer {
private:int outerPrivate;public:class Inner {public:void display(const Outer& outer) {std::cout << "Inner class accessing outerPrivate: " << outer.outerPrivate << std::endl;}};Outer(int value) : outerPrivate(value) {}void callInner() {Inner inner;inner.display(*this);}
};int main() {//通过callInner调用displayOuter outerObj(42);outerObj.callInner();//创建inner对象调用displayOuter::Inner innerObj;innerObj.display(outerObj);return 0;
}
六、匿名对象
匿名对象是指在创建对象时不指定对象名的对象。在对象的类型后面直接加上一对括号可以创建匿名对象,而不提供对象名。
匿名对象没有对象名,只能在创建的语句中使用,并且通常在该语句执行结束后就会被销毁。
class MyClass {
public:void display() {std::cout << "Object is displayed." << std::endl;}
};int main() {// 创建匿名对象,并调用其成员函数MyClass().display();return 0;
}
如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。
相关文章:

【C++】类与对象(四)——初始化列表|explicit关键字|static成员|友元|匿名对象
前言: 初始化列表,explicit关键字,static成员,友元,匿名对象 文章目录 一、构造函数的初始化列表1.1 构造函数体内赋值1.2 初始化列表 二、explicit关键字三、static成员四、友元4.1 友元函数4.2 友元类 五、内部类六、…...

ChatGPT高效提问—prompt常见用法
ChatGPT高效提问—prompt常见用法 1.1 角色扮演 prompt最为常见的用法是ChatGPT进行角色扮演。通常我们在和ChatGPT对话时,最常用的方式是一问一答,把ChatGPT当作一个单纯的“陪聊者”。而当我们通过prompt为ChatGPT赋予角色属性后,即使…...

使用vite创建vue+ts项目,整合常用插件(scss、vue-router、pinia、axios等)和配置
一、检查node版本 指令:node -v 为什么要检查node版本? Vite 需要 Node.js 版本 18,20。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。 二、创…...

泛型、Trait 和生命周期(上)
目录 1、提取函数来减少重复 2、在函数定义中使用泛型 3、结构体定义中的泛型 4、枚举定义中的泛型 5、方法定义中的泛型 6、泛型代码的性能 每一门编程语言都有高效处理重复概念的工具。在 Rust 中其工具之一就是 泛型(generics)。泛型是具体类型…...
<网络安全>《18 数据安全交换系统》
1 概念 企业为了保护核心数据安全,都会采取一些措施,比如做网络隔离划分,分成了不同的安全级别网络,或者安全域,接下来就是需要建设跨网络、跨安全域的安全数据交换系统,将安全保障与数据交换功能有机整合…...

Kafka 生产调优
Kafka生产调优 文章目录 Kafka生产调优一、Kafka 硬件配置选择场景说明服务器台数选择磁盘选择内存选择CPU选择 二、Kafka Broker调优Broker 核心参数配置服役新节点/退役旧节点增加副本因子调整分区副本存储 三、Kafka 生产者调优生产者如何提高吞吐量数据可靠性数据去重数据乱…...

springboot162基于SpringBoot的体育馆管理系统的设计与实现
体育馆管理系统 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本体育馆管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕…...

Interpolator:在Android中方便使用一些常见的CubicBezier贝塞尔曲线动画效果
说明 方便在Android中使用Interpolator一些常见的CubicBezier贝塞尔曲线动画效果。 示意图如下 import android.view.animation.Interpolator import androidx.core.view.animation.PathInterpolatorCompat/*** 参考* android https://yisibl.github.io/cubic-bezier* 实现常…...

Nacos安装,服务注册,负载均衡配置,权重配置以及环境隔离
1. 安装 首先从官网下载 nacos 安装包,注意是下载 nacos-server Nacos官网 | Nacos 官方社区 | Nacos 下载 | Nacos 下载完毕后,解压找到文件夹bin,文本打开startup.cmd 修改配置如下 然后双击 startup.cmd 启动 nacos服务,默认…...
Vue3导出数据为txt文件
在Vue3中,可以通过使用Blob对象以及URL.createObjectURL()方法导出txt文档。 首先,你需要在Vue组件中创建一个方法来生成txt文档的内容。 //res.value.code 数据源 //type:格式设置 //form.name是下载文件的自定义名字 const downLoad ()&…...
Simulink中getConfigSet用法
目录 语法 说明 示例 获取配置集 getConfigSet的功能是从模型中获取配置集或配置引用。 语法 myConfigObj getConfigSet(model, configObjName) 说明 myConfigObj getConfigSet(model, configObjName) 返回关联到 model 并命名为 configObjName 的配置集或配置引用。 …...

【Algorithms 4】算法(第4版)学习笔记 05 - 2.2 归并排序
文章目录 前言参考目录学习笔记1:归并排序的简单演示1.1:基本思路1.2:归并排序的 demo 演示1.3:代码实现2:自顶向下的归并排序2.1:比较次数与访问次数的证明2.2:代码优化2.3:优化后代…...
mybatis mapper sql include用法实现sql块复用
一、总SQL <select id"getxxxMonitorData"resultType"com.xxx.module.system.dal.dataobject.xxx.xxxDO"><include refid"getxxxMonitorDataBaseSql"></include><include refid"whereContent"></include&…...

正点原子--STM32通用定时器学习笔记(2)
1. 通用定时器输入捕获部分框图介绍 捕获/比较通道的输入部分(通道1) 采样频率:控制寄存器 1(TIMx_CR1)的CKD[1:0] ⬇⬇⬇滤波方式选择: 捕获/ 比较模式寄存器 1(TIMx_CCMR1)的输入捕获部分⬇⬇…...
Flask实现异步调用sqlalchemy的模型类
事情是这样的,我这边需要在一次请求里面,搞一个异步不阻碍的任务,来执行耗时的操作。 一开始,我准备写的代码是这样的: from flask import Flask import time from concurrent.futures import ThreadPoolExecutorexec…...
Pocket2Mol + Generation of Atom Positions生成原子位置的方法有什么?联合概率是什么?
联合概率: 联合概率是统计学中的一个概念,用于描述两个或多个随机事件同时发生的概率。当我们谈论多个变量的联合概率时,我们是在探讨这些变量同时取特定值的概率。 让我们简化一下概念: 假设你有一个骰子(六面&…...
区分手机小程序以及电脑小程序;左滑、导航键返回拦截
1、区分电脑小程序和手机小程序 //区分电脑小程序、手机小程序(目标:手机小程序) // #ifdef MP-WEIXIN uni.getSystemInfo({success: (res) > {// windows | mac为pc端// android | ios为手机端// console.log(getSystemInfo,, res.plat…...

Web APIs 2 事件
Web APIs 2 事件 事件监听案例:广告关闭案例:随机问答 事件监听版本事件类型案例:轮播图完整焦点事件键盘事件输入事件案例:评论字数统计 事件对象获取事件对象事件对象常用属性案例:评论回车发布 环境对象this回调函数…...
网易腾讯面试题精选----90道设计模式面试题及答案
介绍 设计模式是软件开发的重要组成部分,为常见设计问题提供经过验证的解决方案。就设计模式面试候选人可以帮助衡量他们对软件架构的理解、解决问题的能力以及编写可维护和可扩展代码的能力。以下是一些常见的设计模式面试问题和答案,可帮助评估候选人在该领域的知识和专业知…...

程序员的数字化工作台:理解不关机背后的逻辑与需求
目录 程序员为什么不喜欢关电脑? 电脑对程序员的重要性: 工作流程与需求: 数据安全与备份: 即时性与响应: 个人习惯等方面: 程序员为什么不喜欢关电脑? 电脑对程序员的重要性:…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...