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;
}

总结:能够利用所学知识点实现通用的数组。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/801874.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

stable diffusion的从安装到使用

stable-diffusion&#xff0c;一个免费开源的文生图软件&#xff0c;文章主要讲怎么从源码开始安装&#xff0c;以及使用的方式 git地址&#xff1a;https://github.com/AUTOMATIC1111/stable-diffusion-webui 本人电脑环境win10&#xff0c;软件pycharm&#xff0c;需要提前…

Java关键字保留字(共53个)

保留字&#xff08;2个&#xff09; 保留字&#xff08;Reserve Word&#xff09;&#xff1a;即它们在Java现有版本中没有特殊含义&#xff0c;以后版本可能会作为有特殊含义的词&#xff0c;或者该词虽然在Java中没有特殊含义&#xff0c;以后版本也不打算使用&#xff0c;但…

jeecg-boot 3.6使用微服务启动详细配置

1&#xff1a;运行sql文件 2&#xff1a;配置host 路径如下 127.0.0.1 jeecg-boot-redis 127.0.0.1 jeecg-boot-mysql 127.0.0.1 jeecg-boot-nacos 127.0.0.1 jeecg-boot-gateway 127.0.0.1 jeecg-boot-system 127.0.0.1 jeecg-boot-xxljob 127.0.0.1 jeecg-boot-rabbitmq 3…

LeetCode第十五题:三数之和【15/1000 python】

&#x1f464;作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 作者专栏每日更新&#xff1a; LeetCode解锁1000题: 打怪升级之旅 LeetCode解锁1000题: 打怪升级之旅htt…

gitea详细介绍

Gitea 是一个轻量级、易于安装的 Git 服务&#xff0c;提供了类似于 GitHub 的功能&#xff0c;如代码托管、问题追踪、团队合作等。它使用 Go 语言开发&#xff0c;可以在自己的服务器上进行部署&#xff0c;从而实现自托管的 Git 服务。Gitea 具有用户友好的界面&#xff0c;…

数据研发八股文(1)

数据库 hadoop与spark结构 Hadoop和Spark在结构上都包含了多个核心组件&#xff0c;但它们的具体实现和用途有所不同。 Hadoop的结构主要包括HDFS&#xff08;Hadoop Distributed File System&#xff09;和MapReduce。HDFS是一个分布式文件系统&#xff0c;用于存储海量的数据…

【管理咨询宝藏52】AA银行企业文化策略分析报告

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏52】AA银行企业文化策略分析报告 【格式】PPT版本&#xff0c;可编辑 【关键词】战略规划、商业分析、管理咨询 【强烈推荐】这是一套市面上非常…

npm包安装与管理:深入解析命令行工具的全方位操作指南,涵盖脚本执行与包发布流程

npm&#xff0c;全称为Node Package Manager&#xff0c;是专为JavaScript生态系统设计的软件包管理系统&#xff0c;尤其与Node.js平台紧密关联。作为Node.js的默认包管理工具&#xff0c;npm为开发者提供了便捷的方式来安装、共享、分发和管理代码模块。 npm作为JavaScript世…

Unity MySql安装部署与Unity连接 上篇

1.前言 最近项目用到MySql&#xff0c;记录一下安装部署过程。 数据量过大或者需要管理用户数据的时候用mysql的话数据结构比较清晰明了&#xff0c;便于管理。 2.安装MySql Unity版本&#xff1a;2019.4.16 MySql版本&#xff1a;8.2.0 下载地址&#xff1a;MySql 下载…

【数据结构】利用顺序表实现通讯录

文章目录 前言通讯录要求利用顺序表的现有功能代码呈现 前言 这篇文章实现的通讯录利用了笔者上一篇写的有关顺序表的应用 https://blog.csdn.net/2301_77954967/article/details/137360029?spm1001.2014.3001.5502&#xff0c;需要用的朋友自行复制 通讯录要求 1)至少能够…

PostgreSQL入门到实战-第七弹

PostgreSQL入门到实战 PostgreSQL查询语句(四)官网地址PostgreSQL概述PostgreSQL中DISTINCT 语句介绍PostgreSQL中DISTINCT 语句实操更新计划 PostgreSQL查询语句(四) 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https:…

【测试篇】Selenium + Java环境搭建

文章目录 Selenium Java环境搭建配置系统环境变量PATH验证环境是否搭建成功常见问题&解决办法 Selenium Java环境搭建 Java版本最低要求为8&#xff0c;这里默认大家都下载好了Java。&#x1f606; 下载chrome浏览器&#xff08;点我下载&#xff09; 观察chrome版本。…

设备监控公有云

在数字化浪潮的推动下&#xff0c;越来越多的企业开始关注设备监控公有云这一重要领域。设备监控公有云通过云计算技术&#xff0c;实现对设备的远程监控、管理和维护&#xff0c;大大提高了企业的运营效率和管理水平。HiWoo Cloud平台作为领先的设备监控公有云解决方案提供商&…

【数据库】PostgreSQL源码编译安装方式与简单配置(v16.2)

PostgreSQL源码编译安装方式与简单配置&#xff08;v16.2&#xff09; 一、PostgreSQL安装基本介绍1.1 几种PostgreSQL的安装方式1.2 删除原有的PostgreSQL1.3 编译安装过程简介 二、源码编译安装方式详情2.1 下载源代码2.2 编译安装运行 configure执行 make执行 make install …

力扣207.课程表

你这个学期必须选修 numCourses 门课程&#xff0c;记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出&#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示如果要学习课程 ai 则 必须 先学习课程 bi 。 例如…

SSM党员管理系统

一、系统介绍 党员管理系统: 可以方便管理人员对党员管理系统的管理&#xff0c;提高信息管理工作效率及查询效率&#xff0c;有利于更好的为用户提供服务。 主要的模块包括&#xff1a; 1、后台功能&#xff1a; 管理员角色&#xff1a;首页、个人中心&#xff0c;党员管理…

前端开发语言概览:从HTML、CSS到JavaScript

随着互联网的发展&#xff0c;前端开发领域涌现出了许多不同的编程语言和技术&#xff0c;用于构建各种类型的网页和应用程序。本文将介绍几种主流的前端开发语言&#xff0c;包括 HTML、CSS 和 JavaScript&#xff0c;并简要讨论它们在前端开发中的作用和特点。 1. HTML&…

Naiveui将message挂载到axios拦截器

最近在做项目&#xff0c;需要将后端的请求结果打印出来 但是想着&#xff0c;要是这样一个一个手动引入naiveui的msg&#xff0c;那不得累死 于是灵机一动&#xff0c;想着既然所有接口要通过拦截器&#xff0c;为什么不将msg写在拦截器呢 一、定义一个消息挂载文件 // The…

【java面试题-Redis篇-2024】

##java面试题大全 详细面试题-持续更新中-点击跳转 点赞、收藏、加关注 java基础面试题 ##java面试题大全1、什么是 Redis2、Redis 的数据结构类型3、Redis 为什么快4、什么是跳跃表5、什么是 I/O 多路复用6、什么是缓存击穿、缓存穿透、缓存雪崩7、什么是布隆过滤器8、热…

经典文章:卷积神经网络的运作原理

https://brohrer.mcknote.com/zh-Hans/how_machine_learning_works/how_convolutional_neural_networks_work.html 参考资料 https://aitechtogether.com/article/38900.html https://www.ruanyifeng.com/blog/2017/07/neural-network.html http://neuralnetworksanddeeplea…