C++学习——对象数组、成员对象与封闭类
以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。
一、对象数组
对象数组,即数组的每个元素都是某个类的对象。
1、对象数组中的每个元素都需要用构造函数初始化,具体哪些元素用哪些构造函数初始化,取决于定义数组时的写法。
请看下面的例子:
#include<iostream>
using namespace std;class CSample{
public:CSample(){ //构造函数 1cout<<"Constructor 1 Called"<<endl;}CSample(int n){ //构造函数 2cout<<"Constructor 2 Called"<<endl;}
};int main(){cout<<"stepl"<<endl;CSample arrayl[2]; //1,1//类似于CSample arrayl[0](),arrayl[1]() ? 有这种写法吗?cout<<"step2"<<endl;CSample array2[2] = {4, 5};//2,2//类似于CSample arrayl[0](4),arrayl[1](5) ? 有这种写法吗?cout<<"step3"<<endl;CSample array3[2] = {3};//2,1cout<<"step4"<<endl;CSample* array4 = new CSample[2];//1,1delete [] array4;return 0;
}
stepl
Constructor 1 Called
Constructor 1 Called
step2
Constructor 2 Called
Constructor 2 Called
step3
Constructor 2 Called
Constructor 1 Called
step4
Constructor 1 Called
Constructor 1 Called
step1的 array1 数组中的两个元素没有指明如何初始化,那么默认调用无参构造函数初始化,因此输出两行 Constructor 1 Called。
step2的 array2 数组进行了初始化,初始化列表 {4, 5} 可以看作用来初始化两个数组元素的参数,所以 array2[0] 以 4 为参数,调用构造函数 2 进行初始化;array2[1] 以 5 为参数,调用构造函数 2 进行初始化。这导致输出两行 Constructor 2 Called。
step3的 array3 指出了 array3[0] 的初始化方式,没有指出 array3[1] 的初始化方式,因此分别用构造函数 2 和构造函数 1 进行初始化。
step4动态分配了一个 CSample 数组,其中有两个元素,没有指出和参数有关的信息,因此这两个元素都用无参构造函数初始化。
2、在构造函数有多个参数时,数组的初始化列表中要显式地包含对构造函数的调用。
例如下面的程序:
class CTest{
public:CTest(int n){ } //构造函数(1)CTest(int n, int m){ } //构造函数(2)CTest(){ } //构造函数(3)
};
int main(){//三个元素分别用构造函数(1)、(2)、(3) 初始化CTest arrayl[3] = { 1, CTest(1,2) };//像{1, (1,2)}这样行不行呢?//三个元素分别用构造函数(2)、(2)、(1)初始化CTest array2[3] = { CTest(2,3), CTest(1,2), 1};//两个元素指向的对象分别用构造函数(1)、(2)初始化CTest* pArray[3] = { new CTest(4), new CTest(1,2) }; //第13行return 0;
}
上面程序中比较容易令初学者困惑的是第 13 行。
pArray 数组是一个指针数组,其元素不是 CTest 类的对象,而是 CTest 类的指针。第 13 行对 pArray[0] 和 pArray[1] 进行了初始化,把它们初始化为指向动态分配的 CTest 对象的指针,而这两个动态分配出来的 CTest 对象又分别是用构造函数(1)和构造函数(2)初始化的。pArray[2] 没有初始化,其值是随机的,不知道指向哪里。
第 13 行生成了两个 CTest 对象,而不是三个,所以也只调用了两次 CTest 类的构造函数。
二、成员对象与封闭类
1、一些概念理解
如果一个类的成员变量是另一个类的对象,则称该成员变量为“成员对象”,而包含成员对象的类叫封闭类(enclosed class)。
2、封闭类的对象的初始化
创建封闭类的对象时,它包含的成员对象也需要被创建,这就会引发成员对象构造函数的调用。成员对象的构造函数可能有很多个(即函数重载),那如何让编译器知道,成员对象到底是用哪个构造函数进行初始化?这就需要借助封闭类构造函数的初始化列表。
一个简单的示例如下:
#include <iostream>
using namespace std;//1、轮胎类
class Tyre{
public:Tyre(int radius, int width);//轮胎类构造函数的声明void show() const;
private:int m_radius; //半径int m_width; //宽度
};
//轮胎类构造函数的定义
Tyre::Tyre(int radius, int width) : m_radius(radius), m_width(width){ }
void Tyre::show() const {cout << "轮毂半径:" << this->m_radius << "吋" << endl;cout << "轮胎宽度:" << this->m_width << "mm" << endl;
}//2、引擎类
class Engine{
public:Engine(float displacement = 2.0);//引擎类构造函数的声明void show() const;
private:float m_displacement;
};
//引擎类构造函数的定义
Engine::Engine(float displacement) : m_displacement(displacement) {}
void Engine::show() const {cout << "排量:" << this->m_displacement << "L" << endl;
}//3、汽车类
class Car{
public:Car(int price, int radius, int width);//汽车类构造函数的声明void show() const;
private:int m_price; //价格Tyre m_tyre;Engine m_engine;
};
//汽车类构造函数的定义
Car::Car(int price, int radius, int width): m_price(price), m_tyre(radius, width){ };//指明m_tyre对象的初始化方式
void Car::show() const {cout << "价格:" << this->m_price << "¥" << endl;this->m_tyre.show();this->m_engine.show();
}int main()
{Car car(200000, 19, 245);//第51行car.show();return 0;
}
价格:200000¥
轮毂直径:19吋
轮胎宽度:245mm
排量:2L
封闭类构造函数的初始化列表,其写法如下:
封闭类的类名::封闭类的构造函数名(参数表): 成员变量名(参数表),…,成员对象名(参数表)
{//TODO:
}
对于封闭类Car,它有一个成员变量m_price,两个成员对象m_tyre 和 m_engine。而且编译器知道第 51 行的 car 这个对象是用 Car(int price, int radius, int width) 这个构造函数进行初始化的。
(1)对于基本类型的成员变量,比如成员变量 m_price 是 int 类型,其“参数表”中只有一个值,就是初始值,在调用构造函数时,会把这个初始值直接赋给成员变量。比如Car类构造函数的初始化列表中,将初始值 price 赋值给成员变量 m_price。
(2)对于成员对象,“参数表”中存放的是构造函数的参数,它可能只有一个值,也可能有多个值,它指明了该成员对象如何被初始化。比如Car类构造函数的初始化列表中,m_tyre(radius, width)告诉编译器,应该以 radius 和 width 作为参数传入构造函数 Tyre(int radius, int width) 中,来初始化m_tyre这个对象。
(3)这里没有说明 m_engine 该如何处理,此时编译器就认为 m_engine 应该用 Engine 类的无参构造函数初始化,而 Engine 类确实有一个无参构造函数(设置了固定参数而视为无参)。
总之,生成封闭类对象的语句,一定要让编译器能够弄明白其成员对象是如何初始化的,否则就会编译错误。在上面的程序中,如果 Car 类的构造函数没有初始化列表,那么第 51 行就会编译出错,因为编译器不知道该如何初始化 car.m_tyre 对象,因为 Tyre 类没有无参构造函数,而编译器又找不到用来初始化 car.m_tyre 对象的参数。
3、成员对象的消亡
封闭类对象生成时,先执行所有成员对象的构造函数,然后才执行封闭类自己的构造函数。成员对象构造函数的执行次序和成员对象在类定义中的次序一致,与它们在构造函数初始化列表中出现的次序无关。
当封闭类对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数,成员对象析构函数的执行次序和构造函数的执行次序相反,即先构造的后析构,这是 C++ 处理此类次序问题的一般规律。
#include<iostream>
using namespace std;class Tyre {
public:Tyre() { cout << "Tyre constructor" << endl; }~Tyre() { cout << "Tyre destructor" << endl; }
};class Engine {
public:Engine() { cout << "Engine constructor" << endl; }~Engine() { cout << "Engine destructor" << endl; }
};class Car {
private:Engine engine;Tyre tyre;
public:Car() { cout << "Car constructor" << endl; }~Car() { cout << "Car destructor" << endl; }
};int main() {Car car;return 0;
}
Engine constructor
Tyre constructor
Car constructor
Car destructor
Tyre destructor
Engine destructor
相关文章:
C++学习——对象数组、成员对象与封闭类
以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 一、对象数组 对象数组,即数组的每个元素都是某个类的对象。 1、对象数组中的每个元素都需要用构造函数初始化,具体哪些元素用哪些构造函数初始化,…...

解锁机器学习-梯度下降:从技术到实战的全面指南
目录 一、简介什么是梯度下降?为什么梯度下降重要? 二、梯度下降的数学原理代价函数(Cost Function)梯度(Gradient)更新规则代码示例:基础的梯度下降更新规则 三、批量梯度下降(Batc…...

day62:ARMday9,I2c总线通信
作业:按键中断实现LED1、蜂鸣器、风扇 key_in.c: #include "key_in.h"void gpio_init() {//RCC使能//GPIOERCC->MP_AHB4ENSETR | (0x1<<4);//GPIOBRCC->MP_AHB4ENSETR | (0x1<<1);//PE10、PB6、PE9输出模式GPIOE->MODER & ~(0…...

【Python学习笔记】类型/运算/变量/注释
前言 人生苦短,追求生产力,做一只时代风口的猪,应该学python Python语言中,所有的数据都被称之为对象。 1. 对象类型 Python语言中,常用的数据类型有: 整数, 比如 3 小数(也叫浮…...

国内常用源开发环境换源(flutter换源,python换源,Linux换源,npm换源)
flutter换源 使用环境变量:PUB_HOSTED_URL FLUTTER_STORAGE_BASE_URL, upgrade出问题时可能会提示设置FLUTTER_GIT_URL变量。 flutter中国 PUB_HOSTED_URLhttps://pub.flutter-io.cn FLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cn FLUTTER_GIT_URLhtt…...

关于一篇什么是JWT的原理与实际应用
目录 一.介绍 1.1.什么是JWT 二.结构 三.Jwt的工具类的使用 3.1. 依赖 3.2.工具类 3.3.过滤器 3.4.控制器 3.5.配置 3.6. 测试类 用于生成JWT 解析Jwt 复制jwt,并延时30分钟 测试JWT的有效时间 测试过期JWT的解析 四.应用 今天就到这了,希…...
【Method】把 arXiv论文 转换为 HTML5 网页
文章目录 MethodReference https://ar5iv.labs.arxiv.org/ Articles from arXiv.org as responsive HTML5 web pages. 可以将来自 arXiv 的 PDF 论文渲染成 HTML5 网页版本。 Method View any arXiv article URL by changing the X to a 5. 将 arXiv 网址中的 x 换成 5 再回…...
每日一题AC
4.小花和小草正在沙滩上玩挖沙洞的游戏。他们划了一条长度为n米的线作为挖沙洞的参考线路,小花和小草分别从两头开始沿着划好的线开始挖洞,小花每隔a米挖一个洞,小草每隔b米挖一个洞,碰到已经挖过洞的就不需要再挖了。那么&#x…...

后端:推荐 2 个 .NET 操作的 Redis 客户端类库
目录 Redis特点 Redis场景 1. StackExchange.Redis 2. FreeRedis 🚀 快速入门 🎣 Master-Slave (读写分离) 💻 Pipeline (管道)示例 🌌 Redis Cluster (集群) Redis ,是一个高性能(NOSQL)的key-value数据库,Re…...

华泰证券:京东营收增长或短期承压
来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,华泰证券近期发布研报称京东营收增长或短期承压。华泰证券主要观点如下:营收增长或短期承压,聚焦长期内生能力建设 考虑到消费情绪的恢复仍需一定时间,我们预计…...

Java从resources文件下载文档,文档没有后缀名
业务场景:因为公司会对excel文档加密,通过svn或者git上传代码也会对文档进行加密,所以这里将文档后缀去了,这样避免文档加密。 实现思路:将文档去掉后缀,放入resources下,获取输入流࿰…...
【动手学深度学习-Pytorch版】BERT预测系列——BERTModel
本小节主要实现了以下几部分内容: 从一个句子中提取BERT输入序列以及相对的segments段落索引(因为BERT支持输入两个句子)BERT使用的是Transformer的Encoder部分,所以需要需要使用Encoder进行前向传播:输出的特征等于词…...
Python之元组、字典和集合练习
1、餐厅下午茶 (列表与元组 crr66) 某餐厅推出了优惠下午茶套餐活动。顾客可以以优惠的价格从给定的糕点和给定的饮 料中各选一款组成套餐。已知,指定的糕点包括松饼(Muffins)、提拉米苏(Tiramisu)、芝士蛋 糕(Cheese Cake)和三明治(Sandwic…...

【数据结构】归并排序和计数排序(排序的总结)
目录 一,归并排序的递归 二,归并排序的非递归 三,计数排序 四,排序算法的综合分析 一,归并排序的递归 基本思想: 归并采用的是分治思想,是分治法的一个经典的运用。该算法先将原数据进行拆…...

某医疗机构:建立S-SDLC安全开发流程,保障医疗前沿科技应用高质量发展
某医疗机构是头部资本集团旗下专注大健康领域战略性投资与运营的实业公司,市场规模超300亿。该医疗机构已完成数字赋能,形成了标准化、专业化、数字化的疾病和健康管理体系,将进一步规划战略方向,为人工智能纳米技术、高温超导、生…...
验证二叉搜索树的后序遍历序列
LCR 152. 验证二叉搜索树的后序遍历序列 class VerifyTreeOrder:"""LCR 152. 验证二叉搜索树的后序遍历序列https://leetcode.cn/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/description/"""def solution(self, postorder: Lis…...

第三章 内存管理 一、内存的基础知识
目录 一、什么是内存 二、有何作用 三、常用数量单位 四、指令的工作原理 五、装入方式 1、绝对装入 2、可重定位装入(静态重定位) 3、动态运行时装入(动态重定位) 六、从写程序到程序运行 七、链接的三种方式 1、静态…...

【Java学习之道】Java常用集合框架
引言 在Java中,集合框架是一个非常重要的概念。它提供了一种方式,让你可以方便地存储和操作数据。Java中的集合框架包括各种集合类和接口,这些类和接口提供了不同的功能和特性。通过学习和掌握Java的集合框架,你可以更好地管理和…...

logicFlow 流程图编辑工具使用及开源地址
一、工具介绍 LogicFlow 是一款流程图编辑框架,提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow 支持前端研发自定义开发各种逻辑编排场景,如流程图、ER 图、BPMN 流程等。在工作审批配置、机器人逻辑编排、无…...
ATF(TF-A)/OPTEE之动态代码分析汇总
安全之安全(security)博客目录导读 1、ASAN(AddressSanitizer)地址消毒动态代码分析 2、ATF(TF-A)之UBSAN动态代码分析 3、OPTEE之KASAN地址消毒动态代码分析...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...