【C++】泛型编程 ⑭ ( 类模板示例 - 数组类模板 | 容器思想 | 自定义类可拷贝 - 深拷贝与浅拷贝 | 自定义类可打印 - 左移运算符重载 )
文章目录
- 一、容器思想
- 1、自定义类可拷贝 - 深拷贝与浅拷贝
- 2、自定义类可拷贝 - 代码示例
- 3、自定义类可打印 - 左移运算符重载
- 二、代码示例
- 1、Array.h 头文件
- 2、Array.cpp 代码文件
- 3、Test.cpp 主函数代码文件
- 4、执行结果
一、容器思想
1、自定义类可拷贝 - 深拷贝与浅拷贝
上一篇博客 【C++】泛型编程 ⑬ ( 类模板示例 - 数组类模板 | 构造函数和析构函数 的 声明与实现 | 普通成员函数 的 声明与实现 | 外部友元函数 的 声明与实现 ) 中 , 实现了一个 数组 类模板 , 数组 中的 数据元素 是 泛型类型 , 可以是任意类型 ;
也就是说 , 该数组可以存储 任意类型 的数据 , 包括 自定义类对象 ;
该数组 就是一个 数据的容器 ;
数组中 每个元素 插入数据时 , 其本质是一个 拷贝操作 , 数组 的 内存空间 在 声明实际类型 以及 创建 时 , 就已经确定了 , 向数组中插入元素 , 就是将 已有的 数据 拷贝到 已经分配好的内存中 ;
向 数据容器 ( 数组 ) 中插入的数据 , 必须可以被 拷贝 , 如果 不能被拷贝 , 就会出现插入数据失败的问题 ;
容器 中的 类型 可拷贝 , 就是要求 容器中的 数据类型 都是 值语义 , 不是 引用语义 ,
向 容器 中插入元素 , 就是拷贝 数据内容 到容器中 , 要将真实的值拷贝进去 , 不是将 引用地址 拷贝进去 ,
就是 深拷贝 和 浅拷贝 的问题 ;
下面的示例中 , 自定义类中的成员变量 char m_name[32] 是 在定义时 , 直接分配好的 ,
如果 自定义类 中有 指针类型的成员变量 , 如 char* m_name , 涉及到 动态分配内存 , 如果没有定义 拷贝构造函数 , 默认的 拷贝构造函数 是 浅拷贝 函数 , 直接将 指针地址 简单拷贝 , 这就是 不可被拷贝的情况 ;
那么多个 数组元素 就会共享 相同的 堆内存 数据 , 此时就会出现问题 ;
如果遇到了上述问题 , 定义了 char* m_name 成员变量 , 涉及到 动态分配内存 , 那么 该自定义类 必须自己实现 深拷贝 的 拷贝构造函数 ;
编写的类 , 可以存储到 数组类模板 容器 中 , 那么 该类 必须 支持 拷贝工作 , 具体一些就是 深拷贝 工作 ;
2、自定义类可拷贝 - 代码示例
下面简单实现一个类 , 该类中维护了 2 个成员变量 , char m_name[32] 数组变量 和 int m_age 变量 , 这两个 成员 都是在 创建时 就会分配内存空间 , 不存在 深拷贝问题 ;
如果 char m_name[32] 数组变量 改为 char* m_name 指针变量 , 就需要考虑 深拷贝问题了 ;
class Student
{
public:Student(){m_age = 10;strcpy(m_name, "NULL");}Student(const char* name, int age) {strcpy(this->m_name, name);this->m_age = age;}void printT() {cout << "name : " << m_name << " , age : " << m_age << endl;}private:char m_name[32];int m_age;
};
3、自定义类可打印 - 左移运算符重载
数组类模板 中 , 实现了 左移运算符 打印日志 , 如果 数组中 存储 自定义类对象 想要通过 cout 打印出来 , 那么 该自定义类 必须 进行 左移运算符重载操作 ;
声明 左移运算符重载函数 :
class Student
{friend ostream& operator<<(ostream& out, const Student& s);
}
实现 左移运算符重载函数 :
// 重载左移运算符实现
ostream& operator<<(ostream& out, const Student& s) {out << "name : " << s.m_name << " , age : " << s.m_age << " ; ";return out;
}
二、代码示例
1、Array.h 头文件
#pragma once#include "iostream"
using namespace std;template <typename T>
class Array
{// 左移 << 操作符重载// 注意 声明时 , 需要在 函数名 和 参数列表之间 注明 泛型类型 <T>// 实现时 , 不能在 函数名 和 参数列表之间 注明 泛型类型 <T>friend ostream& operator<< <T> (ostream& out, const Array& a);public:// 有参构造函数Array(int len = 0);// 拷贝构造函数Array(const Array& array);// 析构函数~Array();public:// 数组下标 [] 操作符重载// 数组元素类型是 T 类型T& operator[](int i);// 等号 = 操作符重载Array& operator=(const Array& a);private:// 数组长度int m_length;// 指向数组数据内存 的指针// 指针类型 是 泛型类型 TT* m_space;
};
2、Array.cpp 代码文件
#include "Array.h"// 左移 << 操作符重载
// 注意 声明时 , 需要在 函数名 和 参数列表之间 注明 泛型类型 <T>
// 实现时 , 不能在 函数名 和 参数列表之间 注明 泛型类型 <T>
template <typename T>
ostream& operator<< (ostream& out, const Array<T>& a)
{for (int i = 0; i < a.m_length; i++){// 在一行内输入数据, 使用空格隔开, 不换行out << a.m_space[i] << " ";}// 换行out << endl;return out;
}// 有参构造函数
template <typename T>
Array<T>::Array(int len)
{// 设置数组长度m_length = len;// 为数组在堆内存中分配内存// 注意 元素类型为 Tm_space = new T[m_length];cout << " 调用有参构造函数 " << endl;
}// 拷贝构造函数
// 这是一个深拷贝 拷贝构造函数
template <typename T>
Array<T>::Array(const Array<T>& array)
{// 设置数组长度m_length = array.m_length;// 创建数组// 注意 元素类型为 Tm_space = new T[m_length];// 为数组赋值for (int i = 0; i < m_length; i++){m_space[i] = array.m_space[i];}cout << " 调用拷贝构造函数 " << endl;
}// 析构函数
template <typename T>
Array<T>::~Array()
{if (m_space != NULL){// 释放 new T[m_length] 分配的内存 delete[] m_space;m_space = NULL;m_length = 0;}cout << " 调用析构函数 " << endl;
}// 数组下标 [] 操作符重载
template <typename T>
T& Array<T>::operator[](int i)
{return m_space[i];
}// 等号 = 操作符重载
template <typename T>
Array<T>& Array<T>::operator=(const Array<T>& a)
{if (this->m_space != NULL){// 释放 new int[m_length] 分配的内存 delete[] this->m_space;this->m_space = NULL;}// 设置数组长度this->m_length = a.m_length;// 创建数组this->m_space = new T[m_length];// 为数组赋值for (int i = 0; i < m_length; i++){this->m_space[i] = a.m_space[i];}cout << " 调用 等号 = 操作符重载 函数" << endl;// 返回是引用类型// 返回引用就是返回本身// 将 this 指针解引用, 即可获取数组本身return *this;
}
3、Test.cpp 主函数代码文件
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std; // 此处注意, 类模板 声明与实现 分开编写
// 由于有 二次编译 导致 导入 .h 头文件 类模板函数声明 无法找到 函数实现
// 必须 导入 cpp 文件
#include "Array.cpp"class Student
{friend ostream& operator<<(ostream& out, const Student& s);
public:Student(){m_age = 10;strcpy(m_name, "NULL");}Student(const char* name, int age) {strcpy(this->m_name, name);this->m_age = age;}void printT() {cout << "name : " << m_name << " , age : " << m_age << endl;}private:char m_name[32];int m_age;
};// 重载左移运算符实现
ostream& operator<<(ostream& out, const Student& s) {out << "name : " << s.m_name << " , age : " << s.m_age << " ; ";return out;
}int main() {// 验证 有参构造函数Array<Student> array(3);Student s0("Tom", 18), s1("Jerry", 12), s2("Jack", 16);array[0] = s0;array[1] = s1;array[2] = s2;// 遍历数组 打印数组元素for (int i = 0; i < 3; i++) {array[i].printT();}cout << array << endl;// 控制台暂停 , 按任意键继续向后执行system("pause");return 0;
}
4、执行结果
执行结果 :
调用有参构造函数
name : Tom , age : 18
name : Jerry , age : 12
name : Jack , age : 16
name : Tom , age : 18 ; name : Jerry , age : 12 ; name : Jack , age : 16 ;Press any key to continue . . .

相关文章:
【C++】泛型编程 ⑭ ( 类模板示例 - 数组类模板 | 容器思想 | 自定义类可拷贝 - 深拷贝与浅拷贝 | 自定义类可打印 - 左移运算符重载 )
文章目录 一、容器思想1、自定义类可拷贝 - 深拷贝与浅拷贝2、自定义类可拷贝 - 代码示例3、自定义类可打印 - 左移运算符重载 二、代码示例1、Array.h 头文件2、Array.cpp 代码文件3、Test.cpp 主函数代码文件4、执行结果 一、容器思想 1、自定义类可拷贝 - 深拷贝与浅拷贝 上…...
砖家测评:腾讯云标准型S5服务器和s6性能差异和租用价格
腾讯云服务器CVM标准型S5和S6有什么区别?都是标准型云服务器,标准型S5是次新一代云服务器规格,标准型S6是最新一代的云服务器,S6实例的CPU处理器主频性能要高于S5实例,同CPU内存配置下的标准型S6实例要比S5实例性能更好…...
Linux常用命令——blkid命令
在线Linux命令查询工具 blkid 查看块设备的文件系统类型、LABEL、UUID等信息 补充说明 在Linux下可以使用blkid命令对查询设备上所采用文件系统类型进行查询。blkid主要用来对系统的块设备(包括交换分区)所使用的文件系统类型、LABEL、UUID等信息进行…...
ES 万条以外分页检索功能实现及注意事项
背景 以 ES 存储日志,且需要对日志进行分页检索,当数据量过大时,就面临 ES 万条以外的数据检索问题,如何利用滚动检索实现这个需求呢?本文介绍 ES 分页检索万条以外的数据实现方法及注意事项。 需求分析 用 ES 存储数…...
【MySQL】mysql中不推荐使用uuid或者雪花id作为主键的原因以及差异化对比
文章目录 前言什么是UUID?什么是雪花ID?什么是MySql自增ID?优缺点对比UUID:优点1.全球唯一性2.无需数据库支持 缺点1.存储空间大2.索引效率低3.查询效率低 雪花ID:优点1.分布式环境下唯一性 缺点1.依赖于机器时钟2.存储空间较大3.查询效率低 MYSQL自增:优点1.简单…...
【Unity细节】Default clip could not be found in attached animations list.(动画机报错)
👨💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 😶🌫️收录于专栏:unity细节和bug 😶🌫️优质专栏 ⭐【…...
VsCode连接远程Linux编译环境的便捷处理
1.免输登录密码 免输命令的正确方法是使用公钥和私鈅在研发设备,和linux服务器上校验身份。公钥和私钥可在windows系统上生成。公钥要发送到linux服务器。私钥需要通知给本地的ssh客户端程序,相关的操作如下: 生成 SSH Key: 打开…...
【UE】用样条线实现测距功能(下)
目录 效果 步骤 一、实现多次测距功能 二、通过控件蓝图来进行测距 在上一篇(【UE】用样条线实现测距功能(上))文章基础上继续实现多次测距和清除功能。 效果 步骤 一、实现多次测距功能 打开蓝图“BP_Spline”,…...
矩阵知识补充
正交矩阵 定义: 正交矩阵是一种满足 A T A E A^{T}AE ATAE的方阵 正交矩阵具有以下几个重要性质: A的逆等于A的转置,即 A − 1 A T A^{-1}A^{T} A−1AT**A的行列式的绝对值等于1,即 ∣ d e t ( A ) ∣ 1 |det(A)|1 ∣det(A)∣…...
机器学习之数据清洗和预处理
目录 Box_Cox Box_Cox Box-Cox变换是一种用于数据预处理和清洗的方法,旨在使数据更符合统计模型的假设,特别是对于线性回归模型。这种变换通过调整数据的尺度和形状,使其更加正态分布。 Box-Cox变换的定义是: y ( λ ) { y λ − 1 λ , i…...
【SpringBoot系列】SpringBoot日志配置
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
庖丁解牛:NIO核心概念与机制详解 06 _ 连网和异步 I/O
文章目录 Pre概述异步 I/OSelectors打开一个 ServerSocketChannel选择键内部循环监听新连接接受新的连接删除处理过的 SelectionKey传入的 I/O回到主循环 Pre 庖丁解牛:NIO核心概念与机制详解 01 庖丁解牛:NIO核心概念与机制详解 02 _ 缓冲区的细节实现…...
域控操作五:统一熄屏睡眠时间
直接看图路径,我只设置了熄屏,如果要睡眠就下面那个启用设置时间...
2023APMCM亚太杯数学建模选题建议及初步思路
大家好呀,亚太杯数学建模开始了,来说一下初步的选题建议吧: 首先定下主基调,本次亚太杯推荐选择B题。 C题如果想做好,搜集数据难度并不低,并且模型比较简单,此外目前选择的人数过多,…...
ORA-28003: password verification for the specified password failed,取消oracl密码复杂度
自己在测试环境想要使自己的Oracle数据库用户使用简单的密码方便测试,结果指定密码的密码验证失败 SQL> alter user zzw identified by zzw; alter user zzw identified by zzw * ERROR at line 1: ORA-28003: password verification for the specified password…...
【DevOps】Git 图文详解(九):工作中的 Git 实践
本系列包含: Git 图文详解(一):简介及基础概念Git 图文详解(二):Git 安装及配置Git 图文详解(三):常用的 Git GUIGit 图文详解(四)&a…...
外贸自建站服务器怎么选?网站搭建的工具?
外贸自建站服务器用哪个好?如何选海洋建站的服务器? 外贸自建站是企业拓展海外市场的重要手段之一。而在这个过程中,选择一个适合的服务器对于网站的稳定运行和优化至关重要。海洋建站将为您介绍如何选择适合的外贸自建站服务器。 外贸自建…...
010 OpenCV中的4种平滑滤波
目录 一、环境 二、平滑滤波 2.1、均值滤波 2.2、高斯滤波 2.3、中值滤波 2.4、双边滤波 三、完整代码 一、环境 本文使用环境为: Windows10Python 3.9.17opencv-python 4.8.0.74 二、平滑滤波 2.1、均值滤波 在OpenCV库中,blur函数是一种简…...
Oracle-客户端连接报错ORA-12545问题
问题背景: 用户在客户端服务器通过sqlplus通过scan ip登陆访问数据库时,偶尔会出现连接报错ORA-12545: Connect failed because target host or object does not exist的情况。 问题分析: 首先,登陆到连接有问题的客户端数据库上,…...
Linux中的进程程序替换
Linux中的进程程序替换 1. 替换原理2. 替换函数3. 函数解释4. 命名理解程序替换的意义 1. 替换原理 替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的…...
MOF材料与神经形态计算:突破硅基极限的新范式
1. 从随机离子到确定性浮点:后硅计算的新范式在计算技术面临物理极限的今天,金属有机框架(MOF)材料因其埃级离子通道特性获得了2025年诺贝尔化学奖,这为突破传统硅基计算提供了全新可能。MOF通道展现出的天然积分发放(Integrate-and-Fire)动力…...
基于MCP协议构建技术术语翻译服务器:架构、集成与实战
1. 项目概述:一个为技术术语翻译而生的MCP服务器 如果你是一名开发者,尤其是在非英语母语环境下工作,或者你的项目需要面向多语言市场,那么你一定遇到过这样的场景:在阅读英文技术文档、编写代码注释,或者与…...
量子机器学习:原理、算法与工程实践
1. 量子机器学习:当传统算力遇到物理极限 三年前我在处理一个蛋白质折叠预测项目时,第一次真切感受到经典计算机的算力瓶颈。当模型参数超过1亿,即使使用最先进的GPU集群,训练周期仍然长达两周。正是那次经历让我开始关注量子计算…...
别再只用K-Means了!用MATLAB手把手教你搞定更抗噪的K-Medoids聚类(附完整代码)
超越K-Means:用MATLAB实战K-Medoids聚类算法解决噪声数据难题 当你的数据集里混入了异常值,K-Means的表现往往会让你失望——那些偏离群体的数据点像磁铁一样把聚类中心拽离合理位置。这时候,K-Medoids算法就该登场了。与K-Means不同…...
AI写论文秘籍!4款AI论文生成工具,帮你轻松完成学术大作
2025 - 2026年AI论文写作工具:学术写作的得力助手 在2025年的学术写作智能化潮流中,越来越多的人开始尝试使用AI写论文的工具。不过,许多现有的AI论文写作工具在撰写硕士和博士论文等长篇作品时,常常面临着缺乏理论深度和逻辑严谨…...
从电池装配到整车下线:YC8000-Q赋能三菱PLC的产线互联方案
一、行业背景与项目概况1.1 新能源汽车制造行业技术需求新能源汽车制造是高端装备制造的核心赛道,其产线需实现焊接、装配、检测等工序的高度自动化与数据互联互通,核心诉求涵盖设备协同联动、数据实时采集、远程运维效率提升,以保障产品一致…...
唐山正规的纤维水泥板制造厂名声
在建筑材料领域,纤维水泥板凭借其诸多优势得到了广泛应用。唐山作为一个有着深厚工业底蕴的城市,拥有不少正规的纤维水泥板制造厂,并且在业界享有良好的名声。下面我们就一同来探寻唐山纤维水泥板制造厂良好名声背后的秘密。一、产品质量过硬…...
TorchTraceAP:PyTorch视觉模型性能优化新方案
1. TorchTraceAP:计算机视觉模型性能优化的新范式在计算机视觉模型的部署实践中,性能优化始终是工程师们面临的核心挑战。传统方法往往依赖人工分析运行轨迹(trace)数据,不仅耗时耗力,而且难以捕捉复杂的性…...
GAN技术发展与应用:从基础到前沿
1. 生成对抗网络(GAN)技术发展概述生成对抗网络(Generative Adversarial Networks)自2014年由Ian Goodfellow等人提出以来,已成为人工智能领域最具革命性的技术之一。这项技术的核心创新在于通过两个神经网络——生成器…...
终极指南:Agent创业机会,从垂直领域切入
终极指南:Agent创业机会,从垂直领域切入 引言 痛点引入:AI Agent浪潮下,普通创业者/技术人该怎么抢滩? 过去两年的AI技术发展,完全是“天翻地覆”级别的——ChatGPT的诞生把通用大语言模型(LLM&…...
