5,178
社区成员




template<class T> — 类模板
template<typename T> — 函数模板
这两种模板的形式,在作用上是无差别的,唯一用法可能只是在于对函数模板和类模板的区分
typeid
)更好。模板就是建立通用的摸具,大大提高复用性
模板的特点:
模板不可以直接使用,它只是一个框架
模板的通用并不是万能的
C++
void func(int a);
| |
返回值类型 形参类型
T T 使用虚拟类型T来代表
语法:template <typename T> +
后紧跟 + 函数声明或定义
紧跟的这一部分(函数声明或定义)就叫做函数模板
template ---> 声明创建模板
typename ---> 表示其后面的符号是一种数据类型,也可以使用class代替
T ---> 通用的数据类型,名称可替换
模板存在的意义:数据类型的参数化
无数种方式
C++
内置数据类型
void SwapInt(int& x, int& y)
{
int temp = x;
x = y;
y = temp;
}
void SwapDouble(double& x, double& y)
{
double temp = x;
x = y;
y = temp;
}
自定义数据类型
void SwapPerson(Person& x, Person& y);...
C++
//声明一个模板,告诉编译器T是一个通用的数据类型,及告诉编译器模板T后紧跟着的那段代码不要报错!
template<typename T>
void My_Swap(T& x, T& y)
{
T temp = x;
x = y;
y = x;
}
--->模板的使用方式:
int main()
{
//1.自动类型推导
My_Swap(参数1, 参数2);
//2.显示指定类型(推荐 - 隐式类型转换) - 明确告诉编译器你想要的数据类型
My_Swap<数据类型>(参数1, 参数2);---><int>(a, b);
}
注意事项:
T
T
的数据类型1.自动类型推导,必须推导出一致的数据类型T
C++
template<typename T>
void My_Swap(T& x, T& y)
{
...
}
int main()
{
int a = 1, b = 2;
char c = 'a';
My_Swap(a, b);--->true
My_Swap(a, c);--->false
return 0;
}
2.模板必须要确定T
的数据类型
C++
template<typename T>
void func()--->函数体 func() 是函数模板,但没有指定模板参数 T 的具体类型
{
cout<< "func() 的调用" << endl;
}
int main()
{
func();--->也没有在调用 func 时提供类型参数
//如果想调用func(),那么可以给模板显示指定一个数据类型
func<int>();--->这样,就可以调用到func()
return 0;
}
案例描述:
1.逐一解决模板,首先我们需要先建立一个排序模板
#include<iostream>
using namespace std;
template<typename T>
void My_Sort(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
int pos = i;//默认当前i位置下标所对应的元素为最大元素
for (int j = i + 1; j < len; j++)
{
if (arr[pos] < arr[j]) pos = j;
}
//当发现arr[i]不是最大值时,进行交换
if (pos != i) My_Swap(arr[pos], arr[i]);
}
}
void test01()
{
char chArr[] = "udoijqwadcknzx";
My_Sort(chArr, sizeof(chArr) / sizeof(char));
}
int main(){test01();return 0;}
2.在我们搭建排序模板的过程中,我们发现我们还需要一个支持两数交换的模板
C++
template<typename T>
void My_Swap(T& x, T& y)
{
T temp = x;
x = y;
y = temp;
}
3.当我们所有的算法步骤解决后,我们就可以再次利用模板的方式来输出结果了
C++
//输出模板
template<typename T>
void My_Print(T arr[], int len)
{
for (int i = 0; i < len; i++) cout << arr[i] << " ";
}
4.总代码:
#include<iostream>
using namespace std;
//交换模板
template<typename T>
void My_Swap(T& x, T& y)
{
T temp = x;
x = y;
y = temp;
}
//排序模板 - 从大到小
template<typename T>
void My_Sort(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
int pos = i;//默认当前i位置下标所对应的元素为最大元素
for (int j = i + 1; j < len; j++)
{
if (arr[pos] < arr[j]) pos = j;
}
//当发现arr[i]不是最大值时,进行交换
if (pos != i) My_Swap(arr[pos], arr[i]);
}
}
//输出模板
template<typename T>
void My_Print(T arr[], int len)
{
for (int i = 0; i < len; i++) cout << arr[i] << " ";
}
void test01() {
char charArr[] = "dasjhdaxaodnqb";
My_Sort(charArr, sizeof(charArr) / sizeof(char));
My_Print(charArr, sizeof(charArr) / sizeof(char));
}
void test02()
{
int intArr[] = { 4,8,4,3,1,3,1,3,13,3,21,56,46 };
My_Sort(intArr, sizeof(intArr) / sizeof(int));
My_Print(intArr, sizeof(intArr) / sizeof(int));
}
int main()
{
test01();
cout << endl;
test02();
return 0;
}
普通函数与 函数模板 的区别(是否会发生隐式类型转换):
隐式类型转换的常见情况:
char
或short
)赋值给一个较大范围的整数类型(如int
)时,会发生隐式类型转换。例如: C++
char c = 'a';
int i = c; // char类型隐式转换为int类型
输出结果97
C++
int Add(int x, int y) return x + y;
void test()
{
int a = 10;
char c = 'a';
//发生隐式类型转换
cout << Add(a, c) << endl;--->109
}
C++
template<typename T>
void My_Add(T& x, T& y)
{
return x + y;
}
int main()
{
int a = 10;
char c = 'c';
//1.自动类型推导
cout << My_Add(a, c);--->false
//2.显示指定类型
cout << My_Add<int>(a, c);--->true,会发生隐式类型转换
return 0;
}
1.如果函数模板和普通函数都可以实现,优先调用普通函数
2.可以通过空模板参数列表来强制调用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以发生更好的匹配,优先调用函数模板
C++
void My_Print(int a, int b)--->哪怕只有函数声明 void My_Print(int a, int b);
{ 也无法直接调用不加空模板参数列表修饰的函数模板
cout << "调用普通函数" << endl;
}
template<typename T>
void My_Print(T& a, T& b)
{
cout << "调用函数模板" << endl;
}
int main()
{
int a = 10, b = 20;
My_Print(a, b);
return 0;
}
C++
My_Print<>(a, b);
C++
template<typename T>
void My_Print(T& a, T& b)
{
cout << "调用函数模板" << endl;
}
template<typename T>
void My_Print(T& a, T& b, T& c)
{
cout << "调用重载的函数模板" << endl;
}
C++
void My_Print(int a, int b)
{
cout << "调用普通函数" << endl;
}
template<typename T>
void My_Print(T& a, T& b)
{
cout << "调用函数模板" << endl;
}
int main()
{
char c1 = 'a', c2 = 'b';
My_Print(c1, c2);
return 0;
}
总结:当我们使用函数模板时,最好减少使用普通函数,否则容易出现二义性
局限性:
例如:
C++
template<typename T>
void f(T& a, T& b)
{
a = b;
}
如上述代码中,提供一个赋值操作,如果 a 和 b 是一个数组,就无法实现了
再例如:
C++
template<typename T>
void f(T& a, T& b)
{
if(a > b){ ... }
}
如上述代码中,如果 T 的数据类型传入的是像 Pereson 这样的自定义数据类型,也无法正常运行
因此,C++为了解决这种问题,提供了模板的重载,可以为这些特定的数据类型提供具体化的模板
C++
class Person
{
public:
Person(string Name, int Age)
{
this->Name = Name;
this->Age = Age;
}
public:
string Name;
int Age;
};
template<class T>
bool My_Compare(T& x, T& y)
{
return x == y;
}
int main()
{
Person p1("啦啦啦", 20);
Person p2("呦呦呦", 3);
cout << (My_Compare(p1, p2) ? "p1 == p2" : "p1 != p2") << endl;
return 0;
}
C++
class Person
{
public:
bool operator== (const Person& other)
cosnt{
return Name == other.Name && Age == other.Age;
}
};
C++
template<typename T>
bool My_Compare(T& p1, T& p2)--->函数模板声明
{
return p1 == p2;
}
template<> bool My_Compare(Person& p1, Person& p2)
{
return p1.Name == p2.Name && p1.Age == p2.Age;
}
总结:
文章来源: https://blog.csdn.net/2401_87692970/article/details/147032677
版权声明: 本文为博主原创文章,遵循CC 4.0 BY-SA 知识共享协议,转载请附上原文出处链接和本声明。