当前位置: 首页 > news >正文

C++面向对象编程之三:初始化列表、类对象作为类成员、静态成员

初始化列表

C++提供了初始化列表语法,可以用于成员属性初始化。

语法规则:

无参构造函数():属性1(值1), 属性2(值2), ...
{
}有参构造函数(形参1, 形参2, ...):属性1(形参1), 属性2(形参2), ...
{
}

example:写一个怪物类,有怪物id和血量属性,并用初始化列表的形式初始化成员属性

#include <iostream>
using namespace std;class Monster
{public:Monster():m_monsterId(10001), m_blood(1000){}Monster(const int monsterId, const int blood):m_monsterId(monsterId), m_blood(blood){}void print_monster_info(){cout << "怪物id = " << m_monsterId << ",血量 = " << m_blood << endl;}private:int m_monsterId; //怪物idint m_blood; //血量
};int main(int argc, char *argv[])
{Monster m1;m1.print_monster_info();Monster m2(10002, 2000);m2.print_monster_info();return 0;
}

类对象作为类成员

C++中的另一个类的对象可以作为类的成员,我们称为该成员为对象成员。那么这时是先构造对象成员,还是先构造该类呢?答案是先构造对象成员后构造该类,析构函数刚好相反,先析构该类后析构对象成员

example:举一个有趣的例子,有一个技能类,一个怪物类,这时怪物会有技能了,所以在设计怪物类时,会有技能类作为怪物类的成员。用来验证另一个类的对象作为类成员时,先构造对象成员,后构造该类。析构则先析构该类,后析构对象成员。

#include <iostream>
using namespace std;enum SKILL_TYPE
{SUB_DEST_BLOOD_ADD_SELF_BLOOD = 0
};int g_line = 0;class Monster;class Skill
{public:Skill():m_skillType(SUB_DEST_BLOOD_ADD_SELF_BLOOD), m_val(500){g_line++;cout << g_line << "行:Skill()无参构造函数被调用" << endl;}Skill(const int skillType, const int val):m_skillType(skillType), m_val(val){g_line++;cout << g_line << "行:Skill(const int skillType, const int val)有参构造函数被调用" << endl;}Skill(const Skill &s){m_skillType = s.m_skillType;m_val = s.m_val;g_line++;cout << g_line << "行:Skill(const Skill &s)拷贝构造函数被调用" << endl;}~Skill(){g_line++;cout << g_line << "行:~Skill()析构函数被调用" << endl;}//施法void spell(Monster &src, Monster &dest);private:int m_skillType; //技能类型int m_val;
};class Monster
{public:Monster():m_monsterId(10001), m_name("怪物"), m_blood(1000), m_skill(){g_line++;cout << g_line << "行:Monster()无参构造函数被调用" << endl;}Monster(const int monsterId, const string name, const int blood, const int skillType, const int skillVal):m_monsterId(monsterId), m_name(name), m_blood(blood), m_skill(skillType, skillVal){g_line++;cout << g_line << "行:Monster(const int monsterId, const string name, const int blood, const int skillType, const int skillVal)有参构造函数被调用" << endl;}Monster(const Monster &m){m_monsterId = m.m_monsterId;m_name = m.m_name;m_blood = m.m_blood;m_skill = m.m_skill;g_line++;cout << g_line << "行:Monster(const Monster &m)拷贝构造函数被调用" << endl;}void setBlood(const int blood){m_blood = blood;}int getBlood(){return m_blood;}void setName(const int name){m_name = name;}string getName(){return m_name;}//释放技能void spell(Monster &dest){m_skill.spell(*this, dest);}~Monster(){g_line++;cout << g_line << "行:~Monster()析构函数被调用" << endl;}void print_monster_info(){g_line++;cout << g_line << "行:怪物id = " << m_monsterId << ",名字 = " << m_name << ",血量 = " << m_blood <<  endl;}private:int m_monsterId; //怪物idstring m_name; //怪物名字int m_blood; //血量Skill m_skill; //技能
};//施法
void Skill::spell(Monster &src, Monster &dest)
{switch (m_skillType){case SUB_DEST_BLOOD_ADD_SELF_BLOOD:{//destint destBlood = dest.getBlood();destBlood -= m_val;if (destBlood < 0)destBlood = 0;dest.setBlood(destBlood);//srcint srcBlood = src.getBlood();srcBlood += m_val;if (srcBlood < 0)srcBlood = 0;src.setBlood(srcBlood);g_line++;cout << g_line << "行:" << src.getName() << " 攻击了 " << dest.getName() << endl;g_line++;cout << g_line << "行:" << src.getName() << "的血量增加到:" << src.getBlood() << endl;g_line++;cout << g_line << "行:" << dest.getName() << "的血量减少到 " << dest.getBlood() << endl;break;}default:g_line++;cout << g_line << "行:技能类型未处理:" << m_skillType << endl;}
}int main(int argc, char *argv[])
{Monster m1(10001, "雪女", 10000, SUB_DEST_BLOOD_ADD_SELF_BLOOD, 1000);Monster m2(10002, "紫衣仙子", 20000, SUB_DEST_BLOOD_ADD_SELF_BLOOD, 2000);m1.print_monster_info();m2.print_monster_info();m1.spell(m2);    return 0;
}

接下来我们再根据打印结果进行代码分析:

Monster m1(10001, "雪女", 10000, SUB_DEST_BLOOD_ADD_SELF_BLOOD, 1000);
另一个类的对象可以作为类的成员时,会先构造对象成员,再构造改该类,析构则刚好相反,先析构
该类,再析构对象成员。所以执行该语句,调用构造函数的顺序为:
(1)Skill类有参构造函数被调用
(2)Monster类有参构造函数被调用Monster m2(10002, "紫衣仙子", 20000, SUB_DEST_BLOOD_ADD_SELF_BLOOD, 2000);
另一个类的对象可以作为类的成员时,会先构造对象成员,再构造改该类,析构则刚好相反,先析构
该类,再析构对象成员。所以执行该语句,调用构造函数的顺序为:
(1)Skill类有参构造函数被调用
(2)Monster类有参构造函数被调用main函数执行结束时,会调用析构函数释放资源,调用析构函数的顺序为:
(1)m2被析构:Monster类析构函数被调用
(2)m2的m_skill对象成员被析构:Skill类析构函数被调用
(3)m1被析构:Monster类析构函数被调用
(4)m1的m_skill对象成员被析构:Skill类析构函数被调用

静态成员

静态成员包括:

  1. 静态成员变量:就是在成员变量前加上关键词static修饰的成员变量

  1. 所有对象共享一份数据

  1. 可以通过类名进行访问:Monster::ms_counter;

  1. 可以通过对象进行访问:Monster m; m.ms_counter;

  1. 在编译阶段分配内存

  1. 类内声明,类外初始化

  1. 有(public,protected,private)访问权限

  1. 静态成员函数:就是在成员函数前加上关键字static修饰的成员函数

  1. 所有对象共享同一个函数

  1. 可以通过类名进行访问:Monster::getMonsterCounter();

  1. 可以通过对象进行访问:Monster m; m.getMonsterCounter();

  1. 静态成员函数的函数体内只能访问静态成员变量和静态成员函数,不能访问非静态成员变量和非静态成员函数

  1. 有(public,protected,private)访问权限

example:测试静态成员变量,所有对象共享一份,类内声明,类外初始化,以及两种访问方式

#include <iostream>
using namespace std;class Monster
{public:Monster():m_monsterId(0){ms_counter++;}Monster(const int monsterId):m_monsterId(monsterId){ms_counter++;}Monster(const Monster &m){m_monsterId = m.m_monsterId;ms_counter++;}~Monster(){ms_counter--;}static int ms_counter; //怪物个数private:int m_monsterId; //怪物id
};int Monster::ms_counter = 0; //静态成员类外初始化int main(int argc, char *argv[])
{//1.静态成员用类名进行访问cout << "ms_counter = " << Monster::ms_counter << endl;;//2.静态成员用对象进行访问Monster m1;cout << "ms_counter = " << m1.ms_counter << endl;Monster m2;cout << "ms_counter = " << m2.ms_counter << endl;return 0;
}

需要注意的是,静态成员变量也有(public,protected,private)访问权限的,如果我们将以上代码中的,静态成员变量声明为private权限,类外将不能对静态成员变量进行访问

example:测试静态成员函数所有对象共享一份,静态成员函数的函数体内只能访问静态成员变量或静态成员函数,不能访问非静态成员变量和非静态成员函数。以及两种访问方式

#include <iostream>
using namespace std;class Monster
{public:Monster():m_monsterId(0){ms_counter++;}Monster(const int monsterId):m_monsterId(monsterId){ms_counter++;}Monster(const Monster &m){m_monsterId = m.m_monsterId;ms_counter++;}~Monster(){ms_counter--;}static int getMonsterCounter(){return ms_counter;}static void setMonsterCounter(const int counter){ms_counter = counter;cout << "ms_counter = " << getMonsterCounter() << endl;//m_monsterId = 90001; //错误:静态成员函数只能访问静态成员变量或静态成员函数}private:static int ms_counter; //怪物个数int m_monsterId; //怪物id
};int Monster::ms_counter = 0; //静态成员类外初始化int main(int argc, char *argv[])
{//1.静态成员用类名进行访问cout << "ms_counter = " << Monster::getMonsterCounter() << endl;;//2.静态成员用对象进行访问Monster m1;cout << "ms_counter = " << m1.getMonsterCounter() << endl;Monster m2;cout << "ms_counter = " << m2.getMonsterCounter() << endl;return 0;
}

需要注意的是,静态成员函数也有(public,protected,private)访问权限的,如果我们将以上代码中的,静态成员函数声明为private权限,类外将不能对静态成员函数进行访问

好了,关于C++面向对象编程之三:初始化列表、类对象作为类成员、静态成员,先写到这。

相关文章:

C++面向对象编程之三:初始化列表、类对象作为类成员、静态成员

初始化列表C提供了初始化列表语法&#xff0c;可以用于成员属性初始化。语法规则&#xff1a;无参构造函数():属性1(值1), 属性2(值2), ... { }有参构造函数(形参1, 形参2, ...):属性1(形参1), 属性2(形参2), ... { }example&#xff1a;写一个怪物类&#xff0c;有怪物id和血量…...

跨域问题解决方案

目录 1.同源策略 2.解决方案(后端) (1)在后端方法添加CrossOrigin (2)添加CORS过滤器 (3)实现WebMvcConfigure接口&#xff0c;重写addCorsMappings方法 3.解决方案(前端) (1)前端配置代理 1.同源策略 同源策略&#xff08;Same origin policy&#xff09;是一种约定&am…...

Vue3电商项目实战-购物车模块7【20-登录后-批量删除、21-登录后-选中状态修改数量、22-登录后-全选反选、23-登录后-修改规格、24-下单结算】

文章目录20-登录后-批量删除21-登录后-选中状态&修改数量22-登录后-全选反选23-登录后-修改规格24-下单结算20-登录后-批量删除 目标&#xff1a;完成批量删除选中商品&#xff0c;完成清空失效的商品 大概步骤&#xff1a; 完成cart.js模块中的批量删除actions的登录状态…...

软件测试之快速熟悉项目

快速熟悉项目 1、了解项目架构 C/S架构 C/S 代表的是客户端/服务器&#xff08;client/server&#xff09;&#xff0c;这类软件的使用者需要在本地电脑安装客户端程序&#xff0c;例如&#xff1a;QQ。 优点:安全性高。 缺点:一旦软件有更新&#xff0c;用户需要手动下载&am…...

软考高级信息系统项目管理师系列之二十一:项目风险管理

软考高级信息系统项目管理师系列之二十一:项目风险管理 一、项目风险管理内容整理二、项目风险管理1.风险及项目风险管理定义2.项目风险的特点3.风险的分类4.风险成本5.项目风险管理与其他管理的关系三、规划风险管理1.规划风险管理2.输入3.工具与技术4.输出四、识别风险1.识别…...

打包成JAR文件和WAR文件,到底有什么区别?

Spring Boot是一种基于Spring框架的快速开发应用程序的工具&#xff0c;可以轻松地构建可部署的独立应用程序。在使用Spring Boot时&#xff0c;你可能会注意到有两种不同的部署选项&#xff1a;打包成JAR文件和WAR文件。在这篇文章中&#xff0c;我们将深入探讨这两种部署选项…...

STM32 OTA应用开发——通过串口/RS485实现OTA升级(方式1)

STM32 OTA应用开发——通过串口/RS485实现OTA升级&#xff08;方式1&#xff09; 目录STM32 OTA应用开发——通过串口/RS485实现OTA升级&#xff08;方式1&#xff09;前言1 环境搭建2 功能描述3 程序编写3.1 BootLoader部分3.2 APP的制作4 修改工程中的内存配置4.1 Bootloader…...

在教学中常被问到的几个vue3.x与typescript的问题,统一解答

在教学当中&#xff0c;学生在学习vue3.x时&#xff0c;常常会问到typescript和vue3.x之间的关系&#xff0c;感觉这两个技术总是绑在一起的&#xff0c;下面老赵来统一解答一下&#xff1a; 那学vue3.x&#xff0c;为什么要求也要掌握typescript Vue 3.x是一个使用TypeScript编…...

纯css实现超炫酷的星空背景按钮

也是在制作项目时发现的&#xff0c;找了很多demo&#xff0c;一点一点测试&#xff0c;发现这个按钮也是非常的炫酷 用到了几个属性&#xff0c;keyframes&#xff0c;::after,::before 先了解一下他们分别都是干嘛的 keyframes 关键帧 keyframes at-rule 规则通过在动画序…...

openpnp - 贴片前, 放入一块新板子后, 对板子的坐标矫正

文章目录openpnp - 贴片前, 放入一块新板子后, 对板子的坐标矫正概述笔记实验前置条件实验开始建立自己板子上的Mark点封装, 用于自己人工圈定判断Mark点位置是否正确建立mark点封装根据多个mark点, 来精确定位板子左下角原点坐标ENDopenpnp - 贴片前, 放入一块新板子后, 对板子…...

计及需求响应的改进灰狼优化算法求解风、光、柴、储容量优化配置(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…...

Elasticsearch使用——高级篇

1.数据聚合**聚合&#xff08;aggregations&#xff09;**可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a;什么品牌的手机最受欢迎&#xff1f;这些手机的平均价格、最高价格、最低价格&#xff1f;这些手机每月的销售情况如何&#xff1f;实现这些统计功…...

Java网络爬虫-HttpClient工具类

关于用Java进行爬虫的资料网上实在少之又少&#xff0c;但作为以一名对Java刚刚初窥门径建立好兴趣的学生怎么能静得下心用新学的Python去写&#xff0c;毕竟Java是世界上最好的语言嘛 (狗头)关于Java爬虫最受欢迎的一个框架Jsoup常常搭配HttpClient来使用&#xff0c;因为Jsou…...

LeetCode203_203. 移除链表元素

LeetCode203_203. 移除链表元素 一、描述 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2…...

【洛谷 P1443】马的遍历 题解(广度优先搜索)

马的遍历 题目描述 有一个 nmn \times mnm 的棋盘&#xff0c;在某个点 (x,y)(x, y)(x,y) 上有一个马&#xff0c;要求你计算出马到达棋盘上任意一个点最少要走几步。 输入格式 输入只有一行四个整数&#xff0c;分别为 n,m,x,yn, m, x, yn,m,x,y。 输出格式 一个 nmn \t…...

为什么gpt输出有随机性?

以下答案由chatGPT产生&#xff01; 为什么gpt输出有随机性&#xff1f; GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种基于Transformer架构的神经语言模型&#xff0c;它是一个深度学习模型&#xff0c;通过在大规模文本数据上进行预训练&#xff0…...

配置Clion用于STM23开发(Makefile)

前言 对于Clion配置STM32开发环境的教程在网上一搜一大堆&#xff0c;但是大部分都是22年之前的&#xff0c;使用的方法都是在STM32CubeMX生成SW4STM32工程。但是在22年不知道哪个版本后&#xff0c;CubeMX已经不再支持生成SW4STM32工程了&#xff0c;这也是我本人遇到的问题。…...

如何在 Istio 中使用 SkyWalking 进行分布式追踪

在云原生应用中&#xff0c;一次请求往往需要经过一系列的 API 或后台服务处理才能完成&#xff0c;这些服务有些是并行的&#xff0c;有些是串行的&#xff0c;而且位于不同的平台或节点。那么如何确定一次调用的经过的服务路径和节点以帮助我们进行问题排查&#xff1f;这时候…...

HBase高手之路1-Hbase简介

文章目录HBase高手之路1-Hbase简介一、什么是HBase1. HBase简介2. HBase的发展过程二、HBase特点1. 海量存储2. 列式存储3. 极易扩展4. 高并发5. 稀疏6. 强一致性读/写7. 自动分块8. 自动RegionServer故障转移9. Hadoop/HDFS集成10. MapReduce11. Java Client API12. Thrift/RE…...

计算机视觉手指甲标注案例

关键点标注是指识别和标注图像或视频中特定的相关点或区域的过程。在机器学习行业&#xff0c;它经常被用来训练计算机视觉模型&#xff0c;以执行诸如物体检测、分割和跟踪等任务。 关键点注释可用于以下应用&#xff1a; 面部关键点检测&#xff1a;识别图像中人脸上的眼睛…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...