🎬 博客主页:博主链接
🎥 本文由 M malloc 原创,首发于 CSDN🙉
🎄 学习专栏推荐:LeetCode刷题集 数据库专栏 初阶数据结构
🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📆 未来很长,值得我们全力奔赴更美好的生活✨
文章目录
😇本章详情
🐤本篇文章将讲授C++的函数模板相关的知识
😇函数模板的前情介绍
😁现在的C++编译器实现了C++新增的一项特性---函数模板。函数模板。函数模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中的泛型可用具体的类型(如int或double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。由于模板允许以泛型(而不是具体类型)的方式编写程序,因此有时也被称为通用编程。由于类型是用参数表示的,因此模板特性有时也被称为参数化类型。
😇利用函数模板来定义交换函数
📝建立交换模板
c++
template <typename T>
void swap(T& a,T& b)
{
T temp;
temp = a;
a = b;
b = temp;
}
解析
第一行指出,要建立一个模板,并将类型命名为T。关键字template和typename是必需的,除非可以使用关键字class代替typename。另外,必须使用尖括号。类型名可以任意选则(这里为T),只要遵守C++命名规则即可。模板并不创建任何函数,而只是告诉编译器如何定义函数。需要交换int的函数时,编译器将按模板模式创建这样的函数,并用int代替T。同样交换double的函数时,编译器将按模板模式创建这样的函数,并有double代替T。
C++98之前的定义方式
在标准C++98添加关键字typename之前,C++使用关键字class来创建模板
c++
template<class T>
void swap(T& a,T& b)
{
T temp;
temp = a;
a = b;
b = temp;
}
typename关键字使得参数T表示类型这一点更为明显;然而,有大量的代码库是使用关键字class开发的。这两种关键字等价的。
✉重载的模板
💐需要多个对不同类型使用同一种算法的函数时,可使用模板,然而并且所有的类型都使用相同的算法。为满足这种需求,可以向重载常规函数定义那样重载模板定义。和常规重载一样,被重载的模板的函数特征标必须不同。例如,在下方代码中新增了一个交换模板,用于交换两个数组中的元素。原模板的特征标为(T&, T&),而新模板的特征标为(T[], T[], int)。在后一个模板中,最后一个参数的类型为具体类型int,而不是泛型。并非所有的模板参数都必须是模板参数类型。
代码演示
c++
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<list>
using namespace std;
template <typename T>
void Swap(T& a,T& b);// new templatetemplate
template <typename T>
void Swap(T *a,T *b,int n);
void Show(int a[]);
const int Lim = 8;
int main()
{
int i = 10, j = 20;
cout << "i, j =" << i << ", " << j << "\n";
Swap(i, j);
cout << i << j << endl;
int d1[Lim] = { 0,7,0,4,1,7,7,6 };
int d2[Lim] = { 0,7,2,0,1,9,6,9 };
cout << "original arrays:\n";
Show(d1);
Show(d2);
Swap(d1, d2, Lim);
cout << "Swapped array:\n";
Show(d1);
Show(d2);
return 0;
}
template <typename T>
void Swap(T& a, T& b)
{
T temp;
temp = a;
a = b;
b = temp;
}
template <typename T>
void Swap(T a[], T b[], int n)
{
T temp;
for (int i = 0; i < n; i++)
{
temp = a[i];
a[i] = b[i];
b[i] = temp;
}
}
void Show(int a[])
{
cout << a[0] << a[1] << "/";
cout << a[2] << a[3] << "/";
for (int i = 4; i < Lim; i++)
{
cout << a[i];
}
cout << endl;
}
输出
📋模板的局限性
💐假设有如下模板函数:
c++
template <class T>
void f(T a,T b)
{}
通常,代码假定可执行那些操作。例如,下面的代码假定定义了赋值,但
如果T为数组,这种假设将不成立:
a = b
同样,下面的语句假设定义了>,但如果T 为结构,该假设便不成立:
c++
if(a>b)
另外,为数组名定义了运算符>,但由于数组名为地址,因此他比较的是数组的地址,而这可能不是您希望的。
注意
名称空间可以是全局的,也可以位于另一个名称空间中,但不能位于代码块中。因此,在默认的情况下,在名称空间中声明的名称的链接性为外部的(除非它引用了常量)
😇显示具体化
📖假设定义了如下结构:
c++
struct job
{
char name[40];
double salary;
int floor;-
};
🌼;另外,假设希望能够交换两个这种结构的内容。原来的模板使用下面的代码来完成交换:
c++
temp = a;
a = b;
b = temp;
由于C++允许将一个结构赋给另一个结构,因此即使T是一个job结构,上述代码也适用。然而,假设只想交换salary和floor成员,而不交换name成员,则需要使用不同的代码,但Swap()的参数将保持不变(两个job结构的引用),因此无法使用模板重载来提供其他的代码。
然而,可以提供一个具体化函数定义----称为显示具体化(explicit specialization),其中包含所需的代码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。
第三代具体化(ISO/ANSI C C++标准)
- 对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及它们的重载版本。
- 显式具体化的原型和定义应以template<>打头,并通过名称来指出类型。
- 具体化优先于常规模板,而非模板函数优先于具体化和常规模板
下面是用于交换job结构的非模板函数、模板函数和具体化的原型:
c++
void Swap(job &, job &);
template <typename T>
void Swap(T&, T&);
template <> void Swap<job>(job&, job&);
📃如何巩固学习
提示:在学习的过程中,我们需要先自行进行思考,并且多去阅读一些大佬的书籍,俗话说的好,书籍是人类进步的阶梯!
📃本文小结
- C++鼓励程序员在开发程序时使用多个文件。一种有效的组织策略是,使用头文件来定义,为操纵用户类型的函数提供函数原型;并将函数定义放在一个独立的源代码文件中。头文件和源代码文件一起定义和实现了用户定义的类型及其使用方式。最后,将main()和其他使用这些函数的函数放在第三个文件中。
好啦今日的分享到这里就结束啦,我是爱你们的M malloc希望可以帮助到你们噢,最后别忘记三连啦!!