c++模板(函数模板,类中函数模板,类模板)

2023-11-16

作用:

减少程序中的冗余信息。如:多个函数或类的除了参数类型外,其余都完全相同时,可以使用模板来减少重复信息(参考函数重载时,输入参数数量也相同的情况)

1、函数模板

即建立一个通用函数,只不过该函数的返回类型和形参类型都不具体指定,其定义格式如下:

template <typename 类型名>

类型名或void  函数名(类型名 形参表)

{

        函数体

}

template <class 类型名>

类型名或void  函数名(类型名 形参表)

{

        函数体

}

1、此处的类型名是由开发人员自己决定的。 

2、一般不注重向后兼容且愿意输入较长的类型名时,选用typename。

代码示例:

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

template <typename ty_na>
ty_na func_name(ty_na* parameters, int size = 0) {
	ty_na first_num = parameters[size];
	return first_num;
}

int main()
{
	int array_int[] = {1,2,3,4,5};
	int first_num = func_name(array_int, 0);
	cout << first_num << endl;
	return 0;
}

此外,由于函数模板也属于函数,因此也可以对其进行函数重载,重载时,参数和参数数量均可改变:

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

template <class type>
type func_name2(type a, type b)
{
	type c = a - b;
	return c;
}

template <class type>
type func_name2(type x, type b, type k)
{
	type y = k * x + b;
	return y;
}
int main()
{
	int get_c = func_name2(1, 2);
	double get_y = func_name2(2.0, 3.2, 2.0);
	cout << "get_c=" << get_c << endl;
	cout << "get_y=" << get_y << endl;
}

2、类中函数模板

2.1先在头文件的对应类中声明模板函数

class cls1
{
public:
    template<typename T>
    void func(T &args);
}

2.2在对应cpp文件中定义模板函数

    template<typename T>
    void cls1::func(T &args)
    {
        函数体
    }

3、类模板

3.1 基本概念

格式:

template <template 类型名>

class 类名

{

public:

        类型名 成员数据

        成员函数(函数类型名 参数名)

}

 当类模板中的成员函数需要在类外定义时,格式为:

template <typename 类型名>

函数类型名 类名<类型名>::成员函数名(类型名 形参表) {...}

 示例:

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

template <typename num>
class compute
{
public:
	num a, b;
	compute(num x, num y) :a(x), b(y) {};
	num add();
};
template <typename num>
num compute<num>::add(){
	return a + b;
}

int main()
{
	compute<int> result(2, 3);
	cout << result.add() << endl;
}

 此外,类模板可以对模板类型指定默认类型,如:

template <typename TYPE=int>

class CLS{...}

         注意:必须使用显示类型指导调用类模板进行实例化,否则类模板无法识别类型。当类模板有类型默认参数时,可以不实例化对应类型。

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

private:
	Name_T m_Name;
	Age_T m_Age;
};

int main() {

	//Person p1("马蒂", 22);

	//使用显示类型指导调用类模板进行实例化,否则类模板无法识别类型
	Person<string, int> p1("马蒂", 22);
	p1.showPerson();

	Person<string> p2("诺顿", 78);//当类模板有类型默认参数时,可以不实例化对应类型
	p2.showPerson();
	system("pause");
	return 0;
}

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

        一般类中的成员函数是一开始就创建,而类模板中的成员函数在调用时才会被创建

如:下列代码可以生成成功,但在实际运行时必定会报错,这是因为类模板的成员函数在生成时并没有被创建,而发生调用后,才能被编译器检查到是否调用发生错误。

class P1 {
public:
	void func1() {
		cout << "P1" << endl;
	}
};

class P2 {
public:
	void func2() {
		cout << "P2" << endl;
	}
};

template <class T>
class TP {
public:
	T obj;
	void func3() {
		obj.func1();
	}

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

int main() {

	TP<P1> p1{};
	p1.func3();
	p1.func4();
	system("pause");
	return 0;
}

 3.3类模板实例化的对象作为函数参数

        a)指定传入的类型,直接显示对象的数据类型。

        b)对象中的参数变成模板传入。

        c)整个类模板化,将对象类型模板化进行传递。

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

private:
	Name_T m_Name;
	Age_T m_Age;
};

//指定传入的类型,直接显示对象的数据类型。
void func1(Person<string, int>& p) {
	p.showPerson();
}
//将对象中的参数变成模板传入。
template<class T1, class T2>
void func2(Person<T1, T2>& p) {
	p.showPerson();
}
//整个类模板化,将对象类型模板化进行传递。
template<class T_>
void func3(T_& p) {
	p.showPerson();
}

4、多类型模板

当需要返回的值的类型不确定时,可声明返回类型为auto(c++11),此时需要在函数体内使用decltype函数来获取返回值类型:

decltype(计算表达式)  self_typename

 示例:

auto Quick_func::get_max(T1& a, T2& b){
	decltype(a > b ? a : b) out = a > b ? a : b;
	cout << "out:" << out << endl;
	return out;
}


int main()
{
    int a = 20;
	double b = 115.0;
	typedef decltype(a > b ? a : b) outtype;
	outtype out = get_max(a, b);

}

5、类模板与继承

        a)如果父类是类模板,子类必须指定父类的参数类型。

        b)如果想要同样灵活使用的父类的参数,将子类定义为类模板,指定子类的参数类型,将其作为继承到的父类参数类型即可。

        示例:

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

//指定子类的参数类型
class Son1 :public Base<float> {

};

//灵活使用模板参数
template<class T1,class T2> 
class Son2 :public Base<T1> {
	T2 son2_param;
};

6、类模板成员函数类外实现与分文件编写

6.1 定义

        类外实现:

        当类模板的成员函数在类内声明,类外进行实现时,在实现部分中,必须加上类模板同样的template类型定义行,在普通类成员函数作用域的加上显示自定义类型使用,如:

template<class T>

void 类名<T>::函数名(T 形参)

{...}

        分文件编写 :

        由于类模板中的成员函数是在调用时才会生成,因此如果只include写有类模板成员函数声明的头文件会报错,无法链接到成员函数定义。

        解决方法:

        a)直接在调用该成员函数的文件中包含写有类模板成员函数定义的cpp文件

        b)将类模板成员函数定义和声明写在同一个文件中,并将文件后缀改为hpp

6.2 示例 

头文件:

template <class Name_T,class Age_T>
class Person {
public:
	Person(Name_T name, Age_T age);
	void showPerson();
private:
	Name_T m_Name;
	Age_T m_Age;
};

 函数声明文件:

#include "head1.h"

template<class Name_T,class Age_T>
Person<Name_T, Age_T>::Person(Name_T name, Age_T age) {
	this->m_Name = name;
	this->m_Age = age;
}

template <class Name_T, class Age_T>
void Person<Name_T, Age_T>::showPerson() {
	cout << "name:" << this->m_Name << " ";
	cout << "age:" << this->m_Age << endl;
}

main函数文件:

#include "head1.h"
#include "func1.cpp"
int main() {

	Person<string, int>* p = NULL;
	p = new Person<string, int>("Adam", 23);
	p->showPerson();
	delete p;
	system("pause");
	return 0;
}

7、类模板友元

        a)类模板中可以定义友元全局函数,从而直接使用类模板的自定义数据类型。

        b)当只在类模板中声明友元全局函数时,由于编译顺序原因,需要把该友元全局函数定义在类模板的前面,才能让类模板中的友元声明实现,而与此同时,由于友元全局函数定义时,将类模板作为传入参数,需要在该函数定义前“声明”一下有该类模板的存在,否则不能完成函数定义。

template <class Name_T, class Age_T>
class Person;

template <class T1, class T2>
void printPerson2(Person<T1, T2>& p) {
	cout << "name:" << p.m_Name << " ";
	cout << "age:" << p.m_Age << endl;
}

template <class Name_T,class Age_T>
class Person {
	//类内友元
	friend void printPerson1(Person<Name_T, Age_T> &p) {
		cout << "name:" << p.m_Name << " ";
		cout << "age:" << p.m_Age << endl;
	}
	//类外实现友元
	template <class T1, class T2>
	friend void printPerson2(Person<T1, T2>& p);
public:
	Person(Name_T name, Age_T age);
	void showPerson();
private:
	Name_T m_Name;
	Age_T m_Age;
};

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++模板(函数模板,类中函数模板,类模板) 的相关文章

随机推荐

  • 【直播+福利】生产压测环境,如何做好安全保障?

    互联网 数字经济的不断发展使得系统架构不断演变 实现了从 单线程 到 多线程 多组件 再到 分布式 微服务 的一个跨越 分布式系统的复杂程度是公认的 牵一发而动全身 想要保障系统的稳定可用是所有企业的共有难题 生产全链路压测应运而生 可实际
  • Ansible-角色部署LAMP

    配置主机 root ansible cd etc ansible root ansible ansible ls ansible cfg hosts roles root ansible ansible vim hosts dev node
  • [图文]Openfiler应用篇(四) FTP和Quota

    本篇我们讨论openfiler FTP和Quota 磁盘配额 的应用 openfiler FTP和Quota功能必须在开启帐户功能的条件下才能使用 一 FTP应用 1 开启FTP 点击主菜单Services 在Manage Services
  • git的使用和规划

    1 拉取项目 在拉取项目的时候使用git rebase 这样分支管理更加清晰 2 提交项目 commit的时候不要把不希望别人看到的改到都commit上 commit的时候 要检查修改的文件代码书写是否正确 下图中打钩文件为想要提交的文件
  • SQL中EXISTS理解使用

    SQL中EXISTS的理解使用 关联子查询 EXISTS理解使用 关联子查询 在讲述EXISTS用法之前 先讲述一下关联子查询 关联子查询 是指在内查询中需要借助于外查询 而外查询离不开内查询的执行 举个栗子 在Oracle中自带的EMP表
  • Objective-C块block介绍

    块的定义 返回值类型 形参类型 形参1 形参类型 形参2 块执行体 以上是一个块的写法 1 返回值类型可以省略 形参也可以参略 但是形参的括号不能参略 NSLog 123 通常我们需要反复调用块 因为块相当于一个匿名的函数 我们调用它时可以
  • 在VMware中设置ubuntu与Windows共享文件夹

    本机系统 win7 使用vmware安装的unbutu 之前在win7上下载了一些文档和软件 想在虚拟机中使用 结果发现读取不了这些文件 头疼了一下午 从网上搜索了很多资源 发现没有一个完整的文章可以一次搞定 头疼 这里就总结一下我的方法
  • I2C与SPI通信总线协议

    仅以寄存器地址为8Bit的器件为例 例如MPU6500 LSM6DS3 I2C通信协议 I2C 的要点是了解I2C通信帧的组成部分 START起始位 STOP停止位 ACK NACK信号 从机器件地址 从机寄存器地址 I2C读的时序比较繁琐
  • K8S访问控制------认证(authentication )、授权(authorization )体系

    一 账号分类 在K8S体系中有两种账号类型 User accounts 用户账号 即针对human user的 Service accounts 服务账号 即针对pod的 这两种账号都可以访问 API server 都需要经历认证 授权 准
  • Linux根目录爆满,解决(/dev/mapper/rhel-root 98%问题)

    1 首先确定是否是磁盘空间不足 输入命令 df h 查看磁盘信息 发现已经使用率达到96 所有需要删除大文件数据 2 其次查找大文件 du h max depth 1 命令代表寻找当前目录 哪个文件夹占用空间最大 进入根目录 root vl
  • 六级英语词汇

    genuine d enju n fake If this offer is genuine I will gladly accept it 如果这份帮助是真诚的 我将愉快地接受它 一 单词关 whereas we r z conj 然而
  • [YOLO专题-17]:YOLO V5 - 如何把YOLO训练数据集批量转换成带矩形框的图片

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 122344955 目录 前言 第1章
  • 利用Spring框架在前端实现对数据库的增删改查

    在前端页面上显示购物数据库数据 并且可以这增 删 改 查 1 首先在WEB 配置文件
  • 交叉熵:pytorch版本 vs 日常版本

    首先看下平时我们所说的交叉熵 传送门 在信息论中 交叉熵可认为是对预测分布q x 用真实分布p x 来进行编码时所需要的信息量大小 而在机器学习的分类问题中 真实分布p x 是one hot形式 表明独属于one hot中1对应的角标的那个
  • cpuz测试分数天梯图_2015最新cpu天梯图 cpu性能排行榜

    西安兵马俑在线3月19日讯查找排名方法 搜索CPU型号 例如 按Ctrl F键 搜 i7 5960X 这个CPU型号 若需获知个人使用的电脑CPU具体型号 查看计算机属性 或用CPU Z这个软件 常用名词解释 CPUModel 处理器型号
  • vsCode关闭代码检查工具

    在script标签里 第一行输入下面的内容即可 转载于 https www cnblogs com caoxueying2018 p 10062329 html
  • 内核运行环境

    复杂度2 5 机密度2 5 最后更新2021 05 06 AIX内核有两种运行环境 process environment和interrupt environment 用户进程call内核系统调用 或者内核系统调用嵌套call其它系统调用
  • 2023年信息与通信工程国际会议(JCICE 2023)

    会议简介 Brief Introduction 2023年第二届信息与通信工程国际会议 JCICE 2023 会议时间 2023年5月12日 14日 召开地点 中国 成都 大会官网 JCICE 2023 2023 International
  • DeeplabCut安装教程(CPU)版

    DeeplabCut安装教程 CPU 版 文章目录 DeeplabCut安装教程 CPU 版 前言 安装步骤 1 进入官网下载对应的DeepLabCut zip文件 附官网链接 2 解压到任意位置 3 打开Anaconda Navigato
  • c++模板(函数模板,类中函数模板,类模板)

    作用 减少程序中的冗余信息 如 多个函数或类的除了参数类型外 其余都完全相同时 可以使用模板来减少重复信息 参考函数重载时 输入参数数量也相同的情况 1 函数模板 即建立一个通用函数 只不过该函数的返回类型和形参类型都不具体指定 其定义格式