C++基础—模版

C++模板是C++语言中实现泛型编程的核心机制,它允许程序员定义通用的代码框架,这些框架在编译时可以根据提供的具体类型参数生成相应的特定类型实例。

泛型编程的特点代码复用和安全性!

模板主要分为两大类:函数模板类模板


函数模板

基本语法:

template <typename T, typename U, ...> 
函数声明或定义

语法解释:

template     ——声明创建模板

typename   ——表明其后面的 符号为一种数据类型,可以用class代替。

      T           ——这个是通用的数据类型,名称可以替换,通常为大写字母。

函数模板的注意事项:

1.模板类型推导(当函数模板被调用时,编译器会根据传递给模板函数的实际参数自动推导出相应的模板参数类型)时同一个通用类型参数要一致

2.函数模板本身并不生成任何代码。只有当模板被实例化,即编译器根据实际使用的参数类型确定出模板参数 T 的具体值时,才会生成对应的具体函数版本

普通函数和函数模板的区别:

a.普通函数调用时可以发生自动类型转换(隐式类型推导)

#include<iostream>
int main()
{
	int a{ 33 };
	char b = 'a';
	std::cout << a+b<< std::endl;
	return 0;
}

//输出结果是
//130

 在a+b时发生了隐式类型转化,'a'转化为ASCN码值结果是33+97所以结果是130

b.函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换

#include<iostream>
template<class T>
T add(T a, T b)
{
	return a + b;
}
int main()
{
	int a{ 33 };
	char b = 'a';
	std::cout <<add(a,b)<< std::endl;
	return 0;
}

//结果出错!

这个会有错误,没有发生隐式转化

c.如果利用显式指定类型的方式,可以发生隐式类型转换

#include<iostream>
template<class T>
T add(T a, T b)
{
	return a + b;
}
int main()
{
	int a{ 33 };
	char b = 'a';
	std::cout <<add<int>(a,b)<< std::endl;
	return 0;
}

//结果是
//130

 如果将这个代码修改这个,可以正确输出130

函数模版的局限性:

对于函数模板我们需要具体化模板

对于具体化的模板会被优先调用

#include<iostream>
template<class T>
void compare(T a,T b)
{
	if (a==b)
	{
		std::cout << "same" << std::endl;
	}
	else
	{
		std::cout << "Notsame" << std::endl;
	}
}

class first
{
public:
	first(int a) :number(a) {};
	int number;
};

int main()
{
	first s(88),ss(888);
	compare(s, ss);
	return 0;
}

//这个会产生错误

如果具体化模版可以解决这个问题

#include<iostream>
template<class T>
void compare(T& a, T& b)
{
	if (a == b)
	{
		std::cout << "same" << std::endl;
	}
	else
	{
		std::cout << "Notsame" << std::endl;
	}
}

class first
{
public:
	first(int a) :number(a) {};
	int number;
};


//具体化模板的语法

template<>        
void compare(first& a, first& b)
{
	if (a.number == b.number)
	{
		std::cout << "same" << std::endl;
	}
	else
	{
		std::cout << "Notsame" << std::endl;
	}
}

int main()
{
	first s(88),ss(888);
	compare(s, ss);
	return 0;
}

//结果是
//Notsame

普通函数和函数模版的调用:

当普通函数与函数模板都能匹配调用时,编译器通常优先选择普通函数。这是因为普通函数更具体,而函数模板需要经过类型推导和实例化的过程。

#include<iostream>

void put(int a)
{
	std::cout << "普通函数的调用" << std::endl;
}

template<class T>
void put(T a)
{
	std::cout << "模板函数的调用" << std::endl;
}

int main()
{
	int a{ 9 };
	put(a);
	return 0;
}

//结果是
//普通函数的调用

若要强制调用函数模板,可以显式指定模板参数或者空模板参数列表

#include<iostream>

void put(int a)
{
	std::cout << "普通函数的调用" << std::endl;
}

template<class T>
void put(T a)
{
	std::cout << "模板函数的调用" << std::endl;
}

int main()
{
	int a{ 9 };
	put<int>(a);  //put<>(a);
	return 0;
}

//结果是
//模板函数的调用

函数模板也可以进行重载

#include<iostream>

void put(int a)
{
	std::cout << "普通函数的调用" << std::endl;
}

template<class T>
void put(T a)
{
	std::cout << "模板函数的调用" << std::endl;
}

template<class T>
void put(T a,T b)
{
	std::cout << "重载模板函数的调用" << std::endl;
}

int main()
{
	int a{ 9 };
	int b{ 9 };
	put(a,b);
	return 0;
}

//结果是
//重载模板函数的调用

 如果普通函数与模板函数之间模板函数有更好的选择,那会调用模板函数

#include<iostream>

void put(int a)
{
	std::cout << "普通函数的调用" << std::endl;
}

template<class T>
void put(T a)
{
	std::cout << "模板函数的调用" << std::endl;
}

int main()
{
	char a = 'a';
	put(a);
	return 0;
}

//结果是
//模板函数的调用

类模板

基本语法:

类模板的语法与函数模板一致

template <typename T, typename U, ...> 
函数声明或定义

语法解释:

template     ——声明创建模板

typename   ——表明其后面的 符号为一种数据类型,可以用class代替。

      T           ——这个是通用的数据类型,名称可以替换,通常为大写字母。

类模版和函数模版的区别:

1.类模板没有自动类型推导的使用方式(在C++17后有自动推导的使用方式)

正确的举例:

#include<iostream>
#include<string>

template<class T,class Y>
class first
{
public:
	first(T a,Y b):A(a),B(b){}
	T A;
	Y B;
};

int main()
{
	first <int, std::string>secend(44, "haha");
	std::cout << secend.A << "  " << secend.B;
	return 0;	
}

//输出的结果
44  haha

在C++17之前如果不进行显示类型指示,那会发生错误

举例子:

#include<iostream>
#include<string>
template<class T,class Y>
class first
{
public:
	first(T a,Y b):A(a),B(b){}
	T A;
	Y B;
};

int main()
{
	first secend(44, "haha");
	std::cout << secend.A << "  " << secend.B;
	return 0;	
}

2.类模板在模板参数列表中可以有默认参数

#include<iostream>
#include<string>
template<class T,class Y=int>
class first
{
public:
	first(T a,Y b):A(a),B(b){}
	T A;
	Y B;
};

int main()
{
	first <int,std::string>secend(44, "haha");
	std::cout << secend.A << "  " << secend.B;
	return 0;	
}

类模板的默认值与函数参数的默认值的很相似,如果进行了显示类型指示那就会覆盖默认值,如果一个参数被设立了默认值,那这个参数右边所有的参数有都需设立为默认。

类模版成员函数的创建时间

1.普通类中的成员函数一开始就可以创建

2.类模板中的成员函数在调用时才创建

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

类模版作为函数参数

1.指定传入的类型——直接显式对象的数据类型

#include <iostream>  

template <class T>
class MyClass
{
public:
    T value;
    MyClass(T val) : value(val) {}
};

void printValue(MyClass<int> &obj)
{
    std::cout << "Value: " << obj.value << std::endl;
}

int main()
{
    MyClass myIntObject(42);
    printValue(myIntObject);
    return 0;
}

//输出结果是
Value: 42

2.参数模板化——将对象中的参数变为模板参数进行传递

#include <iostream>  
 
template <class T>  
class MyClass 
{  
public:  
    T value;  
    MyClass(T val) : value(val) {}  
};

template <class T>  
void printValue(MyClass<T> obj) 
{  
    std::cout << "Value: " << obj.value << std::endl;  
}  
  
int main() 
{  
    MyClass<int> myIntObject(42);  
    MyClass<double> myDoubleObject(3.14);  
    printValue(myIntObject);  // 自动推导为 MyClass<int>  
    printValue(myDoubleObject); // 自动推导为 MyClass<double>  
    return 0;  
}

3.整个类模板化——将这个对象类型,模板化进行传递 

#include <iostream>  

template <class T>
class MyClass
{
public:
    T value;
    MyClass(T val) : value(val) {}
};

template <class T>
void printValue(T obj)
{
    std::cout << "Value: " << obj.value << std::endl;
}

int main()
{
    MyClass<int> myIntObject(42);
    MyClass<double> myDoubleObject(3.14);
    printValue(myIntObject);  // 自动推导为 MyClass<int>  
    printValue(myDoubleObject); // 自动推导为 MyClass<double>  
    return 0;
}

//输出是
Value: 42
Value: 3.14

类模板成员在类外实现

#include<iostream>
#include<string>
template<class T,class Y>
class first
{
public:
	first(T a, Y b);
	void show();
	T A;
	Y B;
};

//类模板成员函数类外实现
template<class T,class Y>
first<T,Y>::first(T a,Y b)
{
	 A = a;
	 B = b;
}

//成员函数类外实现
template<class T,class Y>
void first<T,Y>::show()
{
	std::cout <<A<<"   " << B;
}

int main()
{
	first <int,std::string>secend(44, "haha");
	secend.show();
	return 0;	
}

//输出的结果是:
44   haha

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

类模板与继承

当类模板碰到继承时,需要注意一下几点:

当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型

如果不想指定,编译器无法给子类分配内存

#include<iostream>
template<class T>
class first
{
public:
	T a;
};

class secend :public first
{
public:
	
};

int main()
{
	class secend AA(33);
}

//会出现错误

如果想灵活指定出父类中T的类型,子类也需要变为类模板

#include<iostream>
template<class T>
class first
{
public:
	T a;
};

class secend :public first<int>
{
public:
	
};

int main()
{
	class secend AA(33);
}

//不会出错

将子类也定义为模板

#include<iostream>
template<class T>
class first
{
public:
	T a;
};

template<class T,class Y>
class secend :public first<Y>
{
public:
	T aa;
	Y b;
	secend(T aaval, Y bval, Y firstaval): first<Y>(firstaval), aa(aaval), b(bval) {}
};

int main()
{
	class secend <int ,int>AA(33,44,55);
}

类模板与友元

掌握类模板配合友元函数的类内和类外实现

全局函数类内实现,直接在类内声明友元即可、

全局函数类外实现,需要提前让编译器知道全局函数的存在

#include <iostream>  
  
template <typename T>  
class MyClass {  
public:  
    MyClass(T value) : data(value) {}  
  
    // 声明友元函数  
    friend void printData(const MyClass<T>& obj);  
  
private:  
    T data;  
};  
  
// 全局函数类内实现(直接在类定义中定义)  
template <typename T>  
void printData(const MyClass<T>& obj) {  
    std::cout << "Data: " << obj.data << std::endl;  
}  
  
int main() {  
    MyClass<int> myObject(42);  
    printData(myObject); // 输出:Data: 42  
    return 0;  
}
#include <iostream>  
  
// 前置声明模板类  
template <typename T> class MyClass;  
  
// 前置声明全局友元函数  
template <typename T>  
void printData(const MyClass<T>& obj);  
  
template <typename T>  
class MyClass {  
public:  
    MyClass(T value) : data(value) {}  
  
    // 声明友元函数  
    friend void printData<>(const MyClass<T>&);  
  
private:  
    T data;  
};  
  
// 全局函数类外实现  
template <typename T>  
void printData(const MyClass<T>& obj) {  
    std::cout << "Data: " << obj.data << std::endl;  
}  
  
int main() {  
    MyClass<int> myObject(42);  
    printData(myObject); // 输出:Data: 42  
    return 0;  
}

类模板份文件书写

在C++中,类模板通常涉及多个文件的组织:头文件(.h 或 .hpp)用于声明模板类,源文件(.cpp)用于实现模板类的方法。但是,由于类模板的特殊性,其声明和实现通常合并到同一个头文件中。

如果将模板的声明放在头文件中,而实现放在源文件中,当其他源文件通过包含头文件使用模板时,编译器无法看到模板的实现,导致无法完成模板实例化。这与普通类不同,普通类的成员函数实现可以分离在源文件中,因为编译器只需要知道类的接口(声明)即可编译依赖该类的代码。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【docker 】push 镜像到私服

查看镜像 docker images把这个hello-world 推送到私服 docker push hello-world:latest 报错了。不能推送。需要标记镜像 标记Docker镜像 docker tag hello-world:latest 192.168.2.1:5000/hello-world:latest 将Docker镜像推送到私服 docker push 192.168.2.1:5000/hello…

Django数据库创建存储及管理

一、什么是ORM Django的ORM(Object-Relational Mapping)是Django框架中一个非常重要的组件。ORM可以让开发者以面向对象的方式操作数据库,而不需要直接编写SQL语句。 具体来说,Django ORM提供了以下功能: 模型定义:开发者可以在Django应用中定义Python类来表示数据库表,这些…

基于寄存器的STM32操作流程

寄存器点灯 寄存器操作STM32的好处是不需要依靠外部文件&#xff0c;自由度更高&#xff0c;更为底层&#xff0c;但也更加繁杂。 通过寄存器点灯&#xff0c;需要按照电路结构与手册配置寄存器&#xff1a; 电路结构如下&#xff1a;可知需配置的GPIO为GPIOB5与GPIOE5。 在…

Docker构建LNMP部署WordPress

前言 使用容器化技术如 Docker 可以极大地简化应用程序的部署和管理过程&#xff0c;本文将介绍如何利用 Docker 构建 LNMP 环境&#xff0c;并通过部署 WordPress 来展示这一过程。 目录 一、环境准备 1. 项目需求 2. 安装包下载 3. 服务器环境 4. 规划工作目录 5. 创…

excel怎么删除条件格式规则但保留格式?

这个问题的意思就是要将设置的条件格式&#xff0c;转换成单元格格式。除了使用VBA代码将格式转换外&#xff0c;还可以用excel自己的功能来完成这个任务。 一、将条件格式“留下来” 1.设置条件格式 选中数据&#xff0c;点击开始选项卡&#xff0c;设置条件格式&#xff0…

2024年 Java 面试八股文——SpringMVC篇

目录 1.简单介绍下你对springMVC的理解? 2.说一说SpringMVC的重要组件及其作用 3.SpringMVC的工作原理或流程 4.SpringMVC的优点 5.SpringMVC常用注解 6.SpringMVC和struts2的区别 7.怎么实现SpringMVC拦截器 8.SpringMvc的控制器是不是单例模式&#xff1f;如果是&am…

XUbuntu24.04之更换国内高速源(二百二十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

无人机+飞行汽车:低空经济新引擎,有望爆发式增长

无人机和飞行汽车作为低空经济的新引擎&#xff0c;正在引领一场全新的交通革命。随着技术的不断进步和政策的支持&#xff0c;低空经济有望成为未来经济发展的重要领域&#xff0c;实现爆发式增长。 首先&#xff0c;无人机和飞行汽车具有独特的优势和应用场景。无人机可以在…

confluence 设置https代理

使用nginx反待confluence并开启https后&#xff0c;登录confluence会一直提示&#xff1a;scheme、proxyName、proxyPort设置错误。 解决办法&#xff1a; find / -name server.xmlvi /opt/atlassian/confluence/conf/server.xml HTTP反代配置 HTTPS反代配置

ue引擎游戏开发笔记(28)——实现第三人称越肩视角

1.需求分析 实现一个第三人称越肩视角 2.操作实现 1.思路&#xff1a;建立一个弹簧臂和摄像机&#xff0c;调整两者位置达到越肩效果。 2.直接在蓝图操作&#xff1a;添加摄像机和弹簧臂&#xff1a; 3.对弹簧臂勾选使用pawn控制旋转&#xff0c;并适当调整摄像机和弹簧臂位置…

[NSSCTF]prize_p1

前言 之前做了p5 才知道还有p1到p4 遂来做一下 顺便复习一下反序列化 prize_p1 <META http-equiv"Content-Type" content"text/html; charsetutf-8" /><?phphighlight_file(__FILE__);class getflag{function __destruct(){echo getenv(&qu…

Vue 组件的三大组成部分

Vue 组件通常由三大组成部分构成&#xff1a;模板&#xff08;Template&#xff09;、脚本&#xff08;Script&#xff09;、样式&#xff08;Style&#xff09; 模板部分是组件的 HTML 结构&#xff0c;它定义了组件的外观和布局。Vue 使用基于 HTML 的模板语法来声明组件的模…

【算法入门教育赛1E】最长公共前缀 - 字符串哈希 | 二分 | C++题解与代码

题目链接&#xff1a;https://www.starrycoding.com/problem/163 题目描述 牢 e e e在 S t a r r y C o d i n g StarryCoding StarryCoding的入门教育赛报名单上遇到了许多名字 s 1 , s 2 , . . . , s n s_1, s_2,...,s_n s1​,s2​,...,sn​&#xff0c;他想知道由这些人的…

网络安全风险里的威胁建模

文章目录 前言一、威胁建模的必要性二、威胁建模的过程三、威胁建模框架及方法1、NIST威胁模型框架2、STRIDE Model框架3、DREAD框架4、PASTA流程5、LINDDUN框架6、TRIKE知识库7、安全决策树四、威胁建模应用实践前言 网络安全的本质是攻防双方的对抗与博弈。然而,由于多种攻…

python学习笔记B-20:序列实战--处理千年虫

将2位数表达的年份&#xff0c;转换为用4位数表达&#xff1a; print("将列表中的2位数年份转换为4位数年份") lst[88,89,90,00,99] print(lst) for index in range(len(lst)):if len(str(lst[index]))2:lst[index] 1900int(lst[index])elif len(str(lst[index]))1…

微信小程序demo-----制作文章专栏

前言&#xff1a;不管我们要做什么种类的小程序都涉及到宣传或者扩展其他业务&#xff0c;我们就可以制作一个文章专栏的页面&#xff0c;实现点击一个专栏跳转到相应的页面&#xff0c;页面可以有科普类的知识或者其他&#xff0c;然后页面下方可以自由发挥&#xff0c;添加联…

网盘——分享文件——逻辑设计

本文主要讲解关于网盘文件操作部分的分享文件的逻辑设计部分&#xff0c;主要步骤如下&#xff1a; 目录 1、实施步骤&#xff1a; 2、代码实现 2.1、添加分享文件协议 2.2、添加取消槽函数 2.3、关联取消选择的槽函数 2.4、添加取消槽函数的定义 2.5、添加全选函数槽函…

小程序地理位置接口权限直接抄作业

小程序地理位置接口有什么功能&#xff1f; 随着小程序生态的发展&#xff0c;越来越多的小程序开发者会通过官方提供的自带接口来给用户提供便捷的服务。但是当涉及到地理位置接口时&#xff0c;却经常遇到申请驳回的问题&#xff0c;反复修改也无法通过&#xff0c;给的理由也…

rabbitMq 0 到1

前言 工作中MQ的使用场景是数不胜数&#xff0c;每个公司的技术选型又不太一样&#xff0c;用的哪个MQ&#xff0c;我们必须要先玩起来&#xff0c;RabbitMQ在windows安装遇到很多问题&#xff0c;博客也是五花八门&#xff0c;算了还是自己搞吧&#xff0c;记录一下&#xff…

C#描述-计算机视觉OpenCV(3):重映射

C#描述-计算机视觉OpenCV&#xff08;3&#xff09;&#xff1a;重映射 前言色彩波形图像重映射 前言 C#描述-计算机视觉OpenCV&#xff08;1&#xff09;&#xff1a;基础操作 C#描述-计算机视觉OpenCV&#xff08;2&#xff09;&#xff1a;图像处理 在前文中&#xff0c;描…
最新文章