C++之初识模版

embedded/2025/1/23 10:09:52/

目录

1.关于模版的介绍

2.函数模版

2.1函数模板概念

2.2函数模板格式

2.3 函数模板的原理

2.4 函数模板的实例化

2.5模板参数的匹配原则

3.类模版

3.1类模板的定义格式

3.2 类模板的实例化


1.关于模版的介绍

  • C++中的模板是一种通用编程工具,它允许程序员编写具有通用性的函数或类,可以适用于不同类型的数据。模板使用泛型编程的概念,即代码可以处理多种不同的数据类型,而不只是特定的类型。
  • 在C++中,有两种类型的模板:函数模板和类模板。                 
  • --->函数模板是一种通用的函数定义,可以用于处理不同类型的参数。函数模板使用一对尖括号 "<>" 包围一个或多个类型参数,这些类型参数在函数定义中可以用作函数参数或返回类型的占位符。在调用函数模板时,编译器会根据实际参数的类型来推导出模板参数的具体类型。
  • --->类模板是一种通用的类定义,可以用于创建具有相同结构但可能使用不同类型的成员的类。类模板的定义使用一对尖括号 "<>" 包围一个或多个类型参数,这些类型参数在类定义中可以用作类的成员变量、成员函数的参数或返回类型的占位符。在实例化类模板时,需要提供实际类型的参数。
  • 使用模板可以提供代码的重用性和灵活性,因为它使得编写可以用于处理不同类型数据的通用代码成为可能。模板还可以提供更好的类型检查,并在编译时进行错误检查。

2.函数模版

2.1函数模板概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

2.2函数模板格式

template<typename T1, typename T2,......,typename Tn>返回值类型 函数名(参数列表){}
演示:
template<typename T>//template<class T>
void Swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}
int main()
{int a = 1, b = 0; double c = 3.1415925, d = 4.2526036;Swap(a, b); Swap(c, d);cout << a << b << c << d << endl;return 0;
}

2.3 函数模板的原理

    函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。
    在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
演示:
template<typename T>//template<class T>
void Swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}
int main()
{int a = 1, b = 0; Swap(a, b); double c = 3.1415925, d = 4.2526036;Swap(c, d);char e = 'a', f = 'b';Swap(e, f);return 0;
}

2.4 函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化
1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
演示:
template<typename T1,typename T2>//template<class T>
void Swap(T1& a, T2& b)
{T tmp = a;a = b;b = tmp;
}
int main()
{int a = 1, b = 0; double c = 3.1415925, d = 4.2526036;Swap(a, b); Swap(c, d);Swap(a, d);return 0;
}

这段代码可以成功运行吗?当然可以,因为我们用typename创建了两个模版参数T1和T2,传参时会发生隐式实例化,即便是a与d参数类型不同,也可以分别实例化,那如果将参数减少为一个呢?

// 专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{return left + right;
}
void Test()
{Add(1, 2); // 与非模板函数匹配,编译器不需要特化Add<int>(1, 2); // 调用编译器特化的Add版本
}

这时候报错了,这是因为a是int类型,d是double类型,如果都交给同一个模版参数那么编译器就不知道要隐式实例化为int还是double类型,这时有两种解决办法:
  1. 将a强制类型转换为double或将d强制类型转换为int;
  2. 使用显式实例化
2. 显式实例化:在函数名后的<>中指定模板参数的实际类型
template<typename V>//template<class T>
void Swap(const V& a,const V& b)
{V tmp = a;a = b;b = tmp;
}
int main()
{int a = 1, b = 0; double c = 3.1415925, d = 4.2526036;Swap<double>(a, d);return 0;
}

注意:这里只是演示显式实例化,交换函数在传参时会产生临时变量,具有常性,因此必须用const类型进行接收,不然权限就被放大了,但const修饰之后不可以更改值,因此还请读者注意!

2.5模板参数的匹配原则

1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{return left + right;
}
void Test()
{Add(1, 2); // 与非模板函数匹配,编译器不需要特化Add<int>(1, 2); // 调用编译器特化的Add版本
}
2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
// 专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{return left + right;
}
void Test()
{Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函
数
}
3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

3.类模版

3.1类模板的定义格式

形式:

template<class T1, class T2, ..., class Tn>
class 类模板名
{// 类内成员定义
};

演示:

template<class T>
class A
{
public:A(int year = 2025, int month = 1, int day = 19);~A(){}
private:T* arr;int _year;int _month;int _day;
};template<class T>//作用域就是一个函数或者就是一个类,提取出来就要加上模板
A<T>::A(int year, int month , int day)//A是类名 A<T>是类型 要区分开来
{cout << year << "-" << month << "-" << day << endl;this->_year = year;this->_month = month;this->_day = day;
}

注意:

  1. 缺省参数只能在声明时候标注,在定义的时候标注会引发冲突;
  2. 一般在类中模版参数类型为class,而普通函数模版参数类型为typename;
  3. 类中函数在类外定义时,需要加上template...因为模版的作用域是一个类或者是一个函数,每当重新定义新的类或者函数,都需要重新加上模版
  4. 类外函数声明在用模版参数时不再是简单的类名::函数名,而需要在类名后加上<模版参数>,这是语法规定!

3.2 类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

演示:
template<class T>
class A
{
public:A(int year = 2025, int month = 1, int day = 19);~A(){}
private:T* arr;int _year;int _month;int _day;
};
template<class T>//作用域就是一个函数或者就是一个类,提取出来就要加上模板
A<T>::A(int year, int month , int day)//A是类名 A<T>是类型 要区分开来
{cout << year << "-" << month << "-" << day << endl;this->_year = year;this->_month = month;this->_day = day;
}
int main()
{A<int> a1;A<double> a2;return 0;
}

在main函数中实例化一个类时,使用<>,中间填入模版类型即可~

补充:

  1. 模板的实参在任何时候都可以省略,模板实参省略意思为隐式实例化,一般情况下都使用隐式实例化,不需指定模板类型参数,让编译器进行推导,但有些情况下编译器推导时可能会有歧义,比如:模板参数只有一个类型T,但是用两个不同类型隐式实例化。

  2. 类模板与模板类所指的是同一概念,类模板是一个类家族,模板类是通过类模板实例化的具体类

  3. 类模板的参数可以是虚拟类型的,也可以是具体类型,C++中类模板的参数即为模板参数列表中内容,有两种方式:类型参数和非类型参数,类型参数:即类型参数化,将来实例化为具体的实际类型,有点像函数的形参,形参可以接受不同值的实参;非类型参数:在定义时给定了具体的类型,用该类型定义的为常量。

  4. 类模板中的成员函数全是模板函数,定义时都必须通过完整的模板语法进行定义。 因为所有类模板的成员函数,放在类外定义时,需要在函数名前加类名,而类名实际为ClassName<T>,所以定义时还需加模板参数列表。

- - - - - - ————————————本文结束———————————— - - - - - -


http://www.ppmy.cn/embedded/156274.html

相关文章

数据结构——堆(介绍,堆的基本操作、堆排序)

我是一个计算机专业研0的学生卡蒙Camel&#x1f42b;&#x1f42b;&#x1f42b;&#xff08;刚保研&#xff09; 记录每天学习过程&#xff08;主要学习Java、python、人工智能&#xff09;&#xff0c;总结知识点&#xff08;内容来自&#xff1a;自我总结网上借鉴&#xff0…

C++:将字符数组rkpryyrag,每个字母转换为其前面第13个字母后输出,如果超过a则从z再继续接着数。例如:b前面第1个字母是a。a前面第3个字母是x。

代码如下&#xff1a; #include <iostream> #include <string> using namespace std;int main(){string str "rkpryyrag";for (int i 0; i < str.length(); i){if (str[i] > a && str[i] < z){if (str[i] - a < 13){cout <<…

ASP.NET Blazor部署方式有哪些?

今天我们来说说Blazor的三种部署方式&#xff0c;如果大家还不了解Blazor&#xff0c;那么我先简单介绍下Blazor Blazor 是一种 .NET 前端 Web 框架&#xff0c;在单个编程模型中同时支持服务器端呈现和客户端交互性&#xff1a; ● 使用 C# 创建丰富的交互式 UI。 ● 共享使用…

机器学习(5):支持向量机

1 介绍 支持向量机&#xff08;Support Vector Machine&#xff0c;简称 SVM&#xff09;是一种监督学习算法&#xff0c;主要用于分类和回归问题。SVM 的核心思想是找到一个最优的超平面&#xff0c;将不同类别的数据分开。这个超平面不仅要能够正确分类数据&#xff0c;还要使…

解决Oracle SQL语句性能问题(10.5)——常用Hint及语法(6)(并行相关Hint)

10.5.3. 常用hint 10.5.3.6. 并行相关Hint 1)parallel:显式的指示优化器为SQL语句或SQL语句中的特定表指定或计算并行度。该Hint具体语法如下所示。 SQL> select|insert|update|delete /*+ parallel[(integer|default|auto|manual)] */ ...; --注: 1)这里,parallel…

图论 八字码

我们可能惊异于某些技巧。我们认为这个技巧真是巧妙啊。或者有人认为我依靠自己的直觉想出了这个表示方法。非常自豪。我认为假设是很小的时候&#xff0c;比如说小学初中&#xff0c;还是不错的。到高中大学&#xff0c;就有一些不成熟了。因为这实际上是一个竞技。很多东西前…

【Elasticsearch】RestClient操作文档

RestClient操作文档 新增文档实体类API语法 查询文档删除文档修改文档批量导入文档小结 新增文档 将数据库中的信息导入elasticsearch中 以商品数据为例 实体类 定义一个索引库结构对应的实体。 Data ApiModel(description "索引库实体") public class ItemDoc{…

django使用踩坑经历

DRF 使用drf获取序列化后的id visitor_serializer VisitorSaveSerializer(data{…}) if visitor_serializer.is_valid():visitor visitor_serializer.save() visitor_id visitor.pkpostgrepsql踩坑 django使用postgrepsql&#xff0c;使用聚合函数如:sum 等&#xff0c;被…