第一百一十三天学习记录:C++提高:类模板(黑马教学视频)

news2024/11/26 11:34:15

类模板

类模板语法

类模板作用:
建立一个通用类,类中的成员 数据类型可以不具体定制,用一个虚拟的类型来代表。
语法:

template<typename T>
类

解释:
template … 声明创建模板
typename … 表面其后面的符号是一种数据类型,可以用class代替
T … 通用的数据类型,名称可以替换,通常为大写字母

#include <iostream>
using namespace std;
#include <string>

template<class NameType,class AgeType>
struct Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson()
	{
		cout << "name:" << this->m_Name << "age:" << this->m_Age << endl;
	}
	NameType m_Name;
	AgeType m_Age;
};

void test01()
{
	Person<string, int>p1("孙悟空", 999);
	p1.showPerson();
}

int main()
{
	test01();
	return 0;
}

总结:类模板和函数模板语法相似,在声明模板template后面加类,此类称为模板

类模板与函数模板区别

类模板与函数模板区别主要有两点:
1、类模板没有自动类型推导的使用方式
2、类模板在模板参数列表中可以有默认参数

#include <iostream>
using namespace std;
#include <string>

template<class NameType, class AgeType = int>
struct Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson()
	{
		cout << "name:" << this->m_Name << "age:" << this->m_Age << endl;
	}
	NameType m_Name;
	AgeType m_Age;
};

//1、类模板没有自动类型推导的使用方式
void test01()
{
	//Person p1("孙悟空", 999);//报错,无法用自动类型推导
	Person<string, int>p1("孙悟空", 999);
	p1.showPerson();
}
//2、类模板在模板参数列表中可以有默认参数
void test02()
{
	Person<string>p2("猪八戒",999);
	p2.showPerson();
}

int main()
{
	test01();
	test02();
	return 0;
}

总结:
1、类模板使用只能用显示指定类型方式
2、类模板中的模板参数列表可以有默认参数

类模板中成员函数的创建时机

类模板中成员函数和普通类中成员函数创建时机是有区别的:
1、普通类中的成员函数一开始就可以创建
2、类模板中的成员函数在调用时才创建

#include <iostream>
using namespace std;

class Person1
{
public:
	void showPersong1()
	{
		cout << "Person1 show" << endl;
	}
};

class Person2
{
public:
	void showPersong2()
	{
		cout << "Person2 show" << endl;
	}
};

template<class T>
class Myclass
{
public:
	T obj;
	//类模板中的成员函数
	void func1()
	{
		obj.showPerson1();
	}

	void func2()
	{
		obj.showPerson2();
	}
};

int main()
{

	return 0;
}

上述代码可以运行,因为没有调用成员函数。

#include <iostream>
using namespace std;

class Person1
{
public:
	void showPerson1()
	{
		cout << "Person1 show" << endl;
	}
};

class Person2
{
public:
	void showPerson2()
	{
		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();//报错
}

int main()
{
	test01();
	return 0;
}

总结:
类模板中的成员函数并不是一开始就创建的,在调用时才去创建

类模板对象做函数参数

学习目的:
类模板实例化出的对象,向函数传参的方式
一共有三种传入方式:
1、指定传入的类型 —— 直接显示对象的数据类型
2、参数模板化 —— 将对象中的参数变为模板进行传递
3、整个类模板化 —— 将这个对象类型模板化进行传递

#include <iostream>
using namespace std;
#include <string>

//类模板对象做函数参数
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 printPerson1(Person<string, int>&p)
{
	p.showPerson();
}

void test01()
{
	Person<string, int>p("张三", 33);
	printPerson1(p);
}

//2、参数模板化 —— 将对象中的参数变为模板进行传递
template<class T1, class T2>
void printPerson2(Person<T1, T2>&p)
{
	p.showPerson();
	cout << "T1的类型为:" << typeid(T1).name() << endl;
	cout << "T2的类型为:" << typeid(T2).name() << endl;
}

void test02()
{
	Person<string, int>p("李四", 32);
	printPerson2(p);
}

//3、整个类模板化 —— 将这个对象类型模板化进行传递
template<class T>
void printPerson3(T &p)
{
	p.showPerson();
	cout << "T的数据类型为:" << typeid(T).name() << endl;
}

void test03()
{
	Person<string, int>p("王五", 35);
	printPerson3(p);
}

int main()
{
	test01();
	test02();
	test03();
	return 0;
}

在这里插入图片描述
总结:
1、通过类模板创建的对象,可以有三种方式向函数中进行传参
2、使用比较广泛的是第一种:指定传入的类型

类模板与继承

当类模板碰到继承时,需要注意以下几点:
1、当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
2、如果不指定,编译器无法给子类分配内存
3、如果想灵活指定出父类中T的类型,子类也需变为类模板

#include <iostream>
using namespace std;

template<class T>
class Base
{
	T m;
};

//class Son :public Base//错误,必须要知道父类中T的类型,才能继承给子类
class Son :public Base<int>
{

};

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 test01()
{
	Son s1;
}

void test02()
{
	Son2<int, char>S2;
}

int main()
{
	//test01();
	test02();
	return 0;
}

在这里插入图片描述
总结:如果父类是类模板,子类需要指出父类父类中T的数据类型

类模板成员函数类外实现

学习目标:能够掌握类模板中的成员函数类外实现

#include <iostream>
using namespace std;
#include <string>

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 << "年龄:" << this->m_Age << endl;
}

void test01()
{
	Person<string, int>P("Tom", 20);
	P.showPerson();
}

int main()
{
	test01();
	return 0;
}

总结:类模板中成员函数类外实现时,需要加上模板参数列表

类模板分文件编写

学习目标:
掌握类模板成员函数分文件编写产生的问题以及解决方式

问题:
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决:
1、解决方式1:直接包含.cpp源文件
2、解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制
hpp

#pragma once
#include <iostream>
using namespace std;
#include <string>

//类模板分文件编写问题以及解决

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 << "年龄:" << this->m_Age << endl;
}

main

//第一种解决方式,直接包含源文件
//#include "person.cpp"//少用
//第二种解决方式,将h和cpp中的内容写到仪器,将后缀改为.hpp文件
#include "person.hpp"


void test01()
{
	Person <string, int>p("Jerry", 18);
	p.showPerson();
}

int main()
{
	test01();
	return 0;
}

总结:主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp

类模板与友元

学习目标:掌握类模板配合友元函数的类内和类外实现

全局函数类内实现-直接在类内声明友元即可
全局函数类外实现-需要提前让编译器知道全局函数的存在

#include <iostream>
using namespace std;
#include <string>

//通过全局函数 打印Person信息
//提前让编译器知道Person类存在
template<class T1, class T2>
class Person;

//类外实现
template<class T1, class T2>
void printPerson2(Person<T1, T2> p)
{
	cout << "类外实现--姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;
}

template<class T1, class T2>
class Person
{
	//全局函数 类内实现
	friend void printPerson(Person<T1, T2> p)
	{
		cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;
	}

	//全局函数 类外实现
	//加空模板参数列表
	//如果全局函数 是类外实现,需要让编译器提前知道这个函数的存在
	friend void printPerson2<>(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;
};

//1、全局函数在类内实现

void test01()
{
	Person<string, int>p("Tom", 20);
	printPerson(p);
}

//2、全局函数在类外实现
void test02()
{
	Person<string, int>p("Jerry", 20);
	printPerson2(p);
}

int main()
{
	test01();
	return 0;
}

总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别。

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

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

相关文章

SpringCloud nacos 集成 gateway ,实现动态路由

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

LeetCode刷题笔记 - 859. 亲密字符串

LeetCode刷题笔记 - 859. 亲密字符串 运行结果 题目注意点 bool buddyStrings(char* s, char* goal) {char d 0;char gd 0;int pair 0;int epair 0;char map[256] {0};if (strlen(s) ! strlen(goal)) {return false;}while (*s ! \0) {if (*s ! *goal) {if (d 0) {d *s;…

《Kali渗透基础》09. 漏洞利用、后渗透

kali渗透 1&#xff1a;漏洞基本介绍1.1&#xff1a;漏洞从哪里来1.2&#xff1a;缓冲区溢出1.3&#xff1a;如何发现漏洞 2&#xff1a;漏洞利用2.1&#xff1a;EXP 选择与修改2.2&#xff1a;避免有害的 EXP 3&#xff1a;后渗透阶段3.1&#xff1a;Linux 上传文件3.2&#x…

前后端分离windows本地nginx解决跨域

下载 http://nginx.org/en/download.html 命令 启动Nginx&#xff1a; nginx.exe start 快速停止或关闭Nginx&#xff1a; nginx.exe -s stop 正常停止或关闭Nginx&#xff1a; nginx.exe -s quit 配置文件修改重装载命令&#xff1a; nginx.exe -s reload 强制停用…

六边形架构

六边形架构 微服务系统架构微服务定义微服务系统设计 传统分层架构六边形架构参考资料 微服务系统架构 需求描述做什么的问题&#xff0c;架构描述怎么做的问题(描述组成系统的各部件及其之间的关系) 微服务定义 下面的定义来自周志明老师的 凤凰架构 微服务是一种通过多个小型…

2023牛客暑期多校第一场部分题解

索引 BCDHJKLM B 官方题解说是乱搞题&#xff0c;而我队友实际上也确实乱搞过去了&#xff08; 就是先随便取两个点&#xff0c;有了两个点之后第三个点肯定选离这两个点构成的直线最远的那个&#xff0c;要不然没法包含整个凸多边形。这个过程可以用个三分。 但是确定了第三…

前端(八)——深入探索前端框架中的Diff算法:优化视图更新与性能提升

&#x1f60a;博主&#xff1a;小猫娃来啦 &#x1f60a;文章核心&#xff1a;深入探索前端框架中的Diff算法&#xff1a;优化视图更新与性能提升 文章目录 前端框架中的Diff算法概述vue和react框架的diff算法React的diff算法&#xff1a;Vue的diff算法&#xff1a; Diff算法在…

实训笔记7.20

实训笔记7.20 7.20一、座右铭二、HDFS宕机之后的副本数的问题三、MapReduce的工作流程&#xff08;简单版本&#xff09;四、Hadoop的序列化问题五、MR程序运行中InputFormat类的作用5.1 作用主要有两个5.2 有一个核心实现类--抽象类FileInputFormat 当输入的数据是文件的时候5…

【图像分类】基于LIME的CNN 图像分类研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 基于LIME&#xff08;Local Interpretable Model-Agnostic Explanations&#xff09;的CNN图像分类研究是一种用于解释CNN模型的方法。LIME是一…

实用的设计模式08——适配器模式

适配器的单词是Adapter&#xff0c;我们在开发时经常碰到叫做XxxAdapter的类&#xff0c;此时一般就是使用了适配器模式&#xff0c;适配器模式是非常常用&#xff0c;本文就对适配器模式做一个简单的介绍 文章目录 1、真实开发场景的问题引入2、适配器模式讲解2.1 核心类及类图…

2021年全国大学生电子设计竞赛H题——用电器分析识别装置

用电器分析识别装置 一、题目要求二、系统方案三、硬件设计3.1、ATT7022电参数采集模块 一、题目要求 任务 设计并制作一个根据电源线电流的电参量信息分析在用电器类别的装置。该装置具有学习和分析识别两种工作模式。在学习模式下&#xff0c;测试并存储用于识别各单件电器的…

百亿规模京东实时浏览记录系统的设计与实现 | 京东云技术团队

1. 系统介绍 浏览记录系统主要用来记录京东用户的实时浏览记录&#xff0c;并提供实时查询浏览数据的功能。在线用户访问一次商品详情页&#xff0c;浏览记录系统就会记录用户的一条浏览数据&#xff0c;并针对该浏览数据进行商品维度去重等一系列处理并存储。然后用户可以通过…

mybatis事物是如何和spring事物整合的

目录 1、mybatis事物管理器 2、SpringManagedTransactionFactory如何处理事物 3、spring事物如何设置connection连接到threadLocal 1、mybatis事物管理器 mybatis事物抽象接口类&#xff1a;Transaction。该接口定义了事物基本方法和获取数据库连接方法 该类有三个实现类Jd…

【本地开发快速添加localstoreage和cookie】

在本地开发时&#xff0c;通常会需要线上开发或测试环境的缓存&#xff0c;然而&#xff0c;如果缓存过多时&#xff0c;一个一个的复制key&#xff0c;value太过麻烦&#xff0c;于是本文介绍了一种快速设置缓存的方法。 cookie 需要用到插件&#xff0c;使用JSON格式导出&am…

PPT逻辑设计与完美呈现

PPT逻辑设计与完美呈现 https://haoxinyunxueyuan.zhixueyun.com/#/study/course/detail/detailInfoCD00——朱宁川 logo设计神器: https://www.zitijia.com/logodiy/index 一 PPT设计 第一章、PPT的灵魂设计-5W PPT灵魂设计(5W) 以终为始&#xff0c;从目标出发 why 目…

136. 只出现一次的数字

题目 题解一&#xff1a;采用map集合 class Solution {public static int singleNumber(int[] nums) {Map map new HashMap<Integer,Integer>();for (int i 0; i < nums.length; i) {//判断key是否重复&#xff0c;重复直接删掉重复的keyif (map.containsKey(nums[i…

JavaWeb 速通Servlet(请求转发和请求重定向)

目录 一、HttpServletRequest 1.简介 : 2.常用方法 : 1 getRequestURI() : 2 getRequestURL() : 3 getRemoteHost() : 4 getHeader(String header) : 5 getParameter(name) : 6 getParameterValues(name) : 7 getMethod() : 8 setAttribute(key, value) : 9 getAttrib…

面试之JVM的储存空间

Java8之后&#xff0c;取消了整个永久代区域&#xff0c;取而代之的是元空间。运行时常量池和静态常量池存放在元空间中&#xff0c;而字符串常量池依然存放在堆中。&#xff08;&#xff09; JVM允许时数据区 程序计数器的特点以及作用 &#xff1f; 1、程序计数器 是一块较…

protobuf学习

protobuf的安装 Windos版安装 下载地址&#xff1a;https://github.com/protocolbuffers/protobuf/releases 选择合适的版本下载 将下载的压缩包解压&#xff0c;把解压后文件的bin目录的路径配置到系统环境比变量Path中 在cmd 中执行 protoc --version 成功就说明安装成功了l…

Vue.js基础简答题

系列文章目录 后续补充 文章目录 系列文章目录前言一、库与框架的区别是什么&#xff1f;二、Vue.js 的核心特性有哪些&#xff1f;三、什么是数据驱动视图&#xff1f;四、MVVM 模型各部分含义是什么&#xff0c;在 Vue.js 中分别对应哪些功能&#xff1f;五、el 选项的作用是…