Linux C++ 023-类模板
Linux C++ 023-类模板
本节关键字:Linux、C++、类模板
相关库函数:getCapacity、getSize
类模板语法
类模板的作用:建立一个通用的类,类中的成员 数据类型可以不具体制定, 用一个虚拟的类型代表语法:
template <typename T>
类解释:
template --- 声明创建模板
typename -- 表名其后面的符号是一种数据类型,可以用class代替
T --- 通用的数据类型,名称可以替换,通常为大写字母
示例:
template<class NameType, class AgeType>
class Person
{
public:Person(NameType name, AgeType age){this->m_Name = name;this->m_Age = age;}void showPerson();NameType m_Name;AgeType m_Age;
};
void showPerson(Person &p)
{cout << "name = " << this->m_Name;cout << "age = " << this->m_Age;
}
void test01()
{Person<string, int> p1("孙悟空", 999);
}
总结:类模板和函数模板语法相似,在声明模板teplate后面加类,此类称为类模板
类模板与函数模板的区别
类模板与函数模板的区别主要有两点:
1、类模板没有自动类型推导的使用方式
2、类模板在模板参数列表中可以有默认参数
template <class NameType, class AgeType = int>
class Person
{
public:Person(NameType name, AgeType age){this->m_Name = name;this->m_Age = age;}NameType m_Name;AgeType m_Age;
};
void showPerson(Person &p)
{cout << "name = " << this->m_Name;cout << "age = " << this->m_Age << endl;
}
void test01()
{ //类模板没有自动类型推导的使用方式//Person p1("111", 1000);Person<string, int> p2("1111", 2000);
}
void test02()
{ //类模板在模板参数列表中可以有默认参数Person<string> p1("2", 2000);
}
总结:
类模板没有自动类型推导的使用方式
类模板在模板参数列表中可以有默认参数
类模板中成员函数创建时机
类模板中成员函数和普通类中成员函数的创建时机是有区别的:
(1)普通类中的成员函数一开始就可以创建
(2)类模板中的成员函数在调用时才创建
示例:
class Person1
{void showPerson1(){cout << "Person1 show" << endl;}};class Person2
{void showPerson1(){cout << "Person2 show" << endl;}
};template<class T>
class MyClass
{
public:T obj;//类模板的成员函数void func1(){obj.showPerson1();}void func2(){obj.showPerson2();}
};void test01()
{ //为调用该函数时编译一次,调用的时候再编译一次MyClass<Person1> m;m.func1();m.func2();
}
总结:
类模板中的成员函数并不是一开始就会创建,而是在调用时才创建
类模板对象做函数参数
一共有三种传入方式:
1、指定传入的类型 --- 直接显示对象的数据类型
2、参数模板化 --- 将对象中的参数变为模板进行传递
3、整个类模板化 --- 将这个对象类型 模板化进行传递
示例:
template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}void showPerson(){cout << "姓名:" << this->m_Name << "年龄:" << this->m_Age << endl;}T1 m_Name;T2 m_Age;
};
//1、指定传入类型
void printfPerson1(Person<string, int> &p)
{p.showPerson();
}
void test01()
{Person<string, int> p("孙悟空", 100);
}
//2、参数模板化
template<class T1, class T2>
void printfPerson2(Person<T1, T2> &p)
{p.showPerson();cout << "T1的类型为:" << typeid(T1).name() << endl;cout << "T2的类型为:" << typeid(T2).name() << endl;
}
void test02()
{Person<string, int> p("猪八戒", 100);
}
//3、整个类模板化
template<class T>
void printfPerson3(T &p)
{p.showPerson();cout << "T的类型为:" << typeid(T).name() << endl;
}
void test03()
{Person<string, int> p("唐僧", 30);
}
总结:
通过类模板创建的对象,可以有三种方式向函数进行传参
使用比较广泛的是第一种,指定传入的类型
类模板与继承
当类模板碰到继承时,需要注意以下几点:
(1)当子类继承的父类是类模板时,子类在声明的时候,要指定出父类中T的类型
(2)如果不指定,编译器无法给子类分配内存
(3)如果想灵活指定出父类中T的类型,子类也需要变为类模板
示例:
template<class T>
class Base
{T m;
};
//当子类继承的父类是类模板时,子类在声明的时候,要指定出父类中T的类型
class Son : public Base<int>
{
}
void test01()
{Son s1;
}
//如果想灵活指定出父类中T的类型,子类也需要变为类模板
template<class T1, class T2>
class Son2 : public Base<T2>
{
public:Son2(){cout << "T1的类型为:" << typeid(T1).name() << endl;cout << "T2的类型为:" << typeid(T2).name() << endl;}T1 obj;
}
void test02()
{Son2<int, char> s2;
}
总结:
当子类继承的父类是类模板时,子类在声明的时候,要指定出父类中T的类型
类模板成员函数类外实现
示例:
template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age);void showPerson();T1 m_Name;T2 m_Age;
};template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{this->m_Name = name;this->m_Age = age;
}template<class T1, class T2>
void Person<T1, T2>::showPerson()
{cout << "姓名:" << this->m_Name << endl;
}
void test01()
{Person<string, int>P("Tom", 20);P.showPerson();
}
类模板分文件编写
问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时连接不到
解决方式1:直接包含.cpp源文件
解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制
示例:
template<class T1, class T2>
class Person
{public:Person(T1 name, T2 age);void showPerson();T1 m_Name;T2 m_Age;
};
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{this->m_Name = name;this->m_Age = age;
}template<class T1, class T2>
void Person<T1, T2>::showPerson()
{cout << "姓名:" << this->m_Name << endl;
}
void test01()
{Person <string, int>p("111", 18);p.showPerson();
}
分文件编写
//person.h
#pragram once
#include <iostream>
using namespace std;template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age);void showPerson();T1 m_Name;T2 m_Age;
};
//person.cpp
#include "person.cpp"//第一种解决方式 直接包含源文件 告诉编译器 声明和实现template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{this->m_Name = name;this->m_Age = age;
}template<class T1, class T2>
void Person<T1, T2>::showPerson()
{cout << "姓名:" << this->m_Name << endl;
}
void test01()
{Person <string, int>p("111", 18);p.showPerson();
}
第二种方式 将.h和.cpp中的内容写到一起,将后缀名改为.hpp文件
//person.hpp 调用时直接包含 #include "person.hpp"
#pragram once
#include <iostream>
using namespace std;template<class T1, class T2>
class Person
{
public:Person(T1 name, T2 age);void showPerson();T1 m_Name;T2 m_Age;
};template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{this->m_Name = name;this->m_Age = age;
}template<class T1, class T2>
void Person<T1, T2>::showPerson()
{cout << "姓名:" << this->m_Name << endl;
}
void test01()
{Person <string, int>p("111", 18);p.showPerson();
}
总结:
主流的解决方法为第二种,将类模板成员函数写到一起,并将后缀名改为.hpp
类模板与友元
全局函数类内实现:直接在类内声明友元即可
全局函数类外实现:需要提前让编译器知道全局函数的存在
示例:
//通过全局函数打印Person信息
template <class T1, class T2>
class Person;template <class T1, class T2>
friend void printfPerson2(Person<T1, T2> p)
{ //到此实现执行后会报错//普通函数的声明,对应函数模板的实现//需要在声明时添加空模板的参数列表cout << "类外实现 - 姓名:" << p.m_Name << endl;
}template <class T1, class T2>
class Person
{
//全局函数在类内实现
friend void printfPerson(Person<T1, T2> p)
{cout << "姓名:" << p.m_Name << endl;
}
//全局函数在类外实现
//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在
//解决方法:直接在最前边实现类外的编写,并在实现前声明Person类的存在
friend void printfPerson2<>(Person<T1, T2> p);
public:
Person(T1 name, T2 Age)
{this->m_Name = name;this->m_Age = age;
}private:T1 m_Name;T2 m_Age;
}
//类外实现
template <class T1, class T2>
friend void printfPerson2(Person<T1, T2> p)
{ //到此实现执行后会报错//普通函数的声明,对应函数模板的实现//需要在声明时添加空模板的参数列表cout << "类外实现 - 姓名:" << p.m_Name << endl;
}
void test01()
{Person<string, int> p("Tom", 15);printfPerson(p);
}
void test02()
{Person<string, int> p("Jerry", 10);printfPerson2(p);
}
总结:
建议全局函数做类内实现,用法简单,而且编译器可以直接识别
类模板案例
案例描述:
1.实现一个通用的数组类,要求如下:
2.可以实现内置数据类型以及自定义数据类型的数据进行存储
3.将数组中的数据存储到堆区
4.构造函数中可以传入数组的容量
5.提供对应的拷贝构造函数以及operator=防止浅拷贝问题
6.提供尾插法和尾删法对数组中的数据进行增加和删除
7.可以通过下标的方式访问数组中的元素
8.可以获取数组中当前元素个数和数组的容量
案例实现:
//MyArray.hpp
#pragram once
#include <iostream>
using namespace std;template <class T>
class MyArray
{
public://构造函数(容量)MyArray(int capacity){cout << "MyArray的有参构造调用" << endl;this->m_Capacity = capacity;this->m_Size = 0;this->pAddress = new T[this->m_Capacity];}//拷贝构造MyArray(const MyArray & arr){cout << "MyArray的拷贝构造调用" << endl;this->m_Capacity = arr.m_Capacity;this->m_Size = arr.Size;//this->pAddress = arr.pAddress;this->pAddress = new T[arr.m_Capacity];//深拷贝for(inrt i=0;i<this->m_Size;i++){this->pAddress[i] = arr.pAddress[i];}}//operator= 防止浅拷贝问题MyArray & operator=(consrt MyArray & arr){cout << "MyArray的operator=构造调用" << endl;//先判断原来堆区是否有数据,如果有 先释放if(this->pAddress != NULL){delete[] this->pAddress;this->pAddress = NULL;this->m_Capacity = 0;this->m_Size = 0;}//深拷贝this->m_Capacity = arr.m_Capacity;this->m_Size = arr.Size;this->pAddress = new T[arr.m_Capacity];for(inrt i=0;i<this->m_Size;i++){this->pAddress[i] = arr.pAddress[i];}return *this;}//尾插法void Push_Back(const T & value){//判断容量是否等于大小if(this->m_Capacity == this->m_Size)return ;this->pAddress[this->m_Size] = value;//在数组末尾插入数据this->m_Size++;//更新数组大小}//尾删法void Pop_Back(){//让用户访问不到最后一个元素if(this->m_Size == 0)return ;this->m_Size--;}//通过下标访问数组中元素 arr[0]=100T& operator[](int index){return this->pAddress[index];}//返回数组的容量int getCapacity(){return this->m_Capaciy;}//返回数组的大小int getSize(){return this->m_Size;}//析构函数~MyArray(){cout << "MyArray的析构函数调用" << endl;if(this->pAddress != NULL){delete[] this->pAddress;this->pAddress = NULL;}}
private://数组 T * pAddress;//指针指向堆区开辟的真实数组//容量int m_Capacity;//大小int m_Size;
};#include "MyArray.hpp"
void test01()
{//测试构造和析构MyArray<int>arr1(5);//测试拷贝构造函数MyArray<int>arr2(arr1);//有参构造、拷贝构造、operator=、析构函数MyArray<int>arr3(100);arr3 = arr1;
}
void printfArray(MyArray <int>& arr)
{for(int i=0;i<arr.getSize();i++){cout << arr[i] << endl;}
}
void test02()
{MyArry <int>arr1(5);for(int i=0;i<5;i++){arr1.Push_Back(i);}cout << "打印输出为:" << endl;printfArray(arr1);cout << "arr1的容量为:" << arr1.getCapacity() << endl;cout << "arr1的大小为:" << arr1.getSize() << endl;MyArry <int>arr2(arr1);arr2.Pop_Back();cout << "arr2尾删后:" << endl;cout << "arr2的容量为:" << arr2.getCapacity() << endl;cout << "arr2的大小为:" << arr2.getSize() << endl;
}//测试自定义数据类型
class Person
{
public:Person() {};Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;
};void printPersonArray(MyArray <Person>& arr)
{for(int i=0;i<arr.getSize();i++){cout << "姓名:" << arr[i].m_Name << endl;}
}
void tets03()
{MaArray<Person> arr(10);Person p1("孙悟空", 999);Person p2("韩信", 20);Person p3("妲己", 20);Person p4("赵云", 20);Person p5("安其拉", 20);//将数据插入到数组中arr.Push_Back(p1);arr.Push_Back(p2);arr.Push_Back(p3);arr.Push_Back(p4);arr.Push_Back(p5);//打印函数printPersonArray(arr);cout << "arr的容量为:" << arr.getCapacity() << endl;cout << "arr的大小为:" << arr.getSize() << endl;
}
总结:能够利用所学知识点实现通用的数组。
相关文章:
Linux C++ 023-类模板
Linux C 023-类模板 本节关键字:Linux、C、类模板 相关库函数:getCapacity、getSize 类模板语法 类模板的作用:建立一个通用的类,类中的成员 数据类型可以不具体制定, 用一个虚拟的类型代表语法: templa…...

Android图形显示架构概览
图形显示系统作为Android系统核心的子系统,掌握它对于理解Android系统很有帮助,下面从整体上简单介绍图形显示系统的架构,如下图所示。 这个框架只包含了用户空间的图形组件,不涉及底层的显示驱动。框架主要包括以下4个图形组件。…...

算法学习17:背包问题(动态规划)
算法学习17:背包问题(动态规划) 文章目录 算法学习17:背包问题(动态规划)前言一、01背包问题:1.朴素版:(二维)2.优化版:(一维…...
axios-mock-adapter使用
文章目录 1. 安装 axios-mock-adapter2. 引入所需的库3. 创建一个模拟适配器实例4. 定义模拟响应5. 在你的代码中使用 axios6. 在测试或开发完成后清理模拟 axios-mock-adapter 是一个用于模拟 axios HTTP 请求的库。它允许你在测试或开发过程中,为 axios 实例提供…...
基于单片机的家用无线火灾报警系统设计
摘 要:针对普通家庭的火灾防范需求,设计一种基于单片机的家用无线智能火灾报警系统。该系统主要由传感器、单片机、无线通信模块、GSM 模块、输入显示模块、声光报警电路和GSM 报警电路组成。系统工作时,检测部分单片机判断是否发生火灾,并将信息通过无线通信模块传…...
LangChain:索引(Indexes)--基础知识
引言 在当今信息爆炸的时代,如何高效地获取、处理和利用信息成为了关键。LangChain,作为一种先进的语言模型框架,提供了强大的索引功能,帮助用户更好地管理和应用文本数据。本文将详细介绍LangChain索引中的几个核心组件…...

Cortex-M4架构
第一章 嵌入式系统概论 1.1 嵌入式系统概念 用于控制、监视或者辅助操作机器和设备的装置,是一种专用计算机系统。 更宽泛的定义:是在产品内部,具有特定功能的计算机系统。 1.2 嵌入式系统组成 硬件 ①处理器:CPU ②存储器…...
对称排序(蓝桥杯)
文章目录 对称排序问题描述模拟 对称排序 问题描述 小蓝是一名软件工程师,他正在研究一种基于交换的排序算法,以提高排序的效率。 给定一个长度为 N 的数组 A,小蓝希望通过交换对称元素的方式对该数组进行排序。 具体来说,小蓝…...

React - 你使用过高阶组件吗
难度级别:初级及以上 提问概率:55% 高阶组件并不能单纯的说它是一个函数,或是一个组件,在React中,函数也可以做为一种组件。而高阶组件就是将一个组件做为入参,被传入一个函数或者组件中,经过一定的加工处理,最终再返回一个组件的组合…...

【C语言】结构体、枚举、联合(自定义类型)
文章目录 前言一、结构体1.结构体的声明2.结构体的自引用3.结构体变量的定义和初始化4.结构体成员的访问5.结构体内存对齐(重点)6.#pragma修改默认对齐数7.结构体传参 二、位段1.位段的声明2.位段的内存分配3.位段的跨平台问题 三、枚举四、联合 &#x…...

用vue.js写案例——ToDoList待办事项 (步骤和全码解析)
目录 一.准备工作 二.编写各个组件的页面结构 三.实现初始任务列表的渲染 四.新增任务 五.删除任务 六.展示未完成条数 七.切换状态-筛选数据 八.待办事项(全)代码 一.准备工作 在开发“ToDoList”案例之前,需要先完成一些准备工作&a…...

提高大型语言模型 (LLM) 性能的四种数据清理技术
原文地址:four-data-cleaning-techniques-to-improve-large-language-model-llm-performance 2024 年 4 月 2 日 检索增强生成(RAG)过程因其增强对大语言模型(LLM)的理解、为它们提供上下文并帮助防止幻觉的潜力而受…...
Rust 练手小项目:猜数游戏
好久没写 Rust 了,参考《Rust 程序设计语言》写了一下猜数游戏。差不多 40 行,感觉写起来真舒服。 use rand::Rng; use std::{cmp::Ordering, io};fn main() {let secret_number rand::thread_rng().gen_range(0..100);println!("[*] Guess the n…...

蓝桥杯物联网竞赛_STM32L071_16_EEPROM
仍然是没有考过的知识点 朴素的讲就是板子中一块不会因为断电重启而导致数值初始化的一片地址 要注意的是有时候容易把板子什么写错导致板子什么地址写坏了导致程序无法烧录,这个时候记得一直按flash键烧录,烧录时会报错,点击确定࿰…...

复习知识点整理
零碎语法 1.导入某个文件夹的index文件,index可以省略(这里导入的是router和store文件下的index.js文件) 2.路由懒加载 this 1.在vue文件中使用router\store对象时 this:普通函数的this指向vue实例对象(在没有明确指向的时候…...

7款公司电脑监控软件
7款公司电脑监控软件 研究证明,人们在家办公的效率比在办公室办公的效率低一半,其中原因是缺少监督,即便在公司办公,还存在员工偷闲的时刻,比如聊天、浏览无关网站、看剧、炒股等,企业想提高员工的工作效率…...

服务器 安装1Panel服务器运维管理面板
服务器 安装1Panel服务器运维管理面板 SSH链接服务器安装1Panel 出现此提示时输入目标路径,须以“/”开头,默认:/opt,本例:/www。 出现此提示时输入目标端口,须未被使用的端口,默认࿱…...
最大花之能量(蓝桥杯)
文章目录 最大花之能量问题描述动态规划 最大花之能量 问题描述 在一个神奇的王国里,有一个美丽的花园,里面生长着各种奇妙的花朵。这些花朵都有一个特殊的能力,它们能够释放出一种叫做「花之能量」的神秘力量。每朵花的花之能量都不同&…...

探索算力(云计算、人工智能、边缘计算等):数字时代的引擎
引言 在数字时代,算力是一种至关重要的资源,它是推动科技创新、驱动经济发展的关键引擎之一。简而言之,算力即计算能力,是计算机系统在单位时间内完成的计算任务数量或计算复杂度的度量。随着科技的不断发展和应用范围的不断扩大…...

数据可视化-ECharts Html项目实战(10)
在之前的文章中,我们学习了如何在ECharts中编写雷达图,实现特殊效果的插入运用,函数的插入,以及多图表雷达图。想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错&…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

《基于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…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...