目录
- 泛型编程
- 函数模板
- 函数模板概念
- 函数模板格式
- 函数模板的原理
- 函数模板的实例化
- 隐式实例化
- 强制类型转换的疑惑
- 显式实例化
- 模板参数的匹配原则
- 类模板
- 类模板的定义格式
- 类模板的实例化
感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录
泛型编程
下面是实现各种类型的交换函数
void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}
上面函数功能完全相同,只是传入的参数类型不同,如果我们在要一一实现的话就太麻烦了,所以如果有一个公用的模板,可以支持不同类型的传参就好了
函数模板
函数模板概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本
函数模板格式
template<typename T1, typename T2,......,typename Tn>这里的T1..代表类型
用函数模板实现交换功能如下
template<typename T>
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}
T代表所有的类型,所以也可以交换char类型的变量
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)
函数模板的原理
上面的模板中不同类型的变量都调用了Swap,现在有一个问题就是Swap(a,b)和Swap(c,d)是否用的同一个Swap函数
事实上他们调用的并不是同一个Swap函数,因为a b的类型和c d的类型是不一样的,也就是函数模版中的T是未知类型,根据传入参数类型生成一个匹配的函数
函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
隐式实例化
让编译器根据实参推演模板参数的实际类型
在上面已经演示过一个例子了
但是如果我们传入的参数不符合模板规定就会报错
这里的Swap模板中的T只能表示一种类型,而我们传入的参数中包含了int类型和double类型,也就是说T的类型即是int也是double,显然这是不可能的,所以出现参数T不明确这个错误
解决方案有三种,第一种是强制类型转换,第二种就是显示实例化,第三种就是用多个不同的T(T1 T2 T3…)
强制类型转换的疑惑
但是关于强制类型转换这里我有一点疑惑
void Swap(T& left, T& right)
{T temp = left;left = right;right = temp;
}
int main()
{int a = 1, b = 2;double c = 1.001, d = 2.001;Swap(a, b);Swap((int)c, a);cout << a << "\n" << b << endl;cout << c << "\n" << d << endl;return 0;
}
按理来说强制类型转换后参数类型就相同了,并且就算double类型和int类型数据进行交换,也应该只是出现数据丢失这种情况,但是不会报错,而这里却出现了问题,所以我不是很清楚
而再看看下面这个例子,在没有强制类型转换前是报错的,而强制类型转换后可以正常运行
显式实例化
在函数名后的<>中指定模板参数的实际类型
template<typename T1>
T1 ADD(const T1& left, const T1 right)
{return left + right;
}
int main()
{int a = 1;double b = 2.001;cout << ADD<int>(a, b) << endl;cout << ADD<double>(a, b) << endl;return 0;
}
Swap函数还是会报错,但是后面我发现了一句话:如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错,可能是因为这个才报错的
但是第三中方法是可以解决这个问题的
template<typename T1,typename T2>
T1 ADD(const T1& left, const T2 right)
{return left + right;
}
int main()
{int a = 1;double b = 2.001;cout << ADD(a, b) << endl;return 0;
}
这里会出现数据丢失,所以输出的结果是3
再来看看Swap会不会报错
template<typename T,typename T1>
void Swap(T& left, T1& right)
{T temp = left;left = right;right = temp;
}int main()
{int a = 1, b = 2;double c = 1.001, d = 2.001;Swap(a, b);Swap(c, a);cout << a << "\n" << b << endl;cout << c << "\n" << d << endl;return 0;
}
c之所以等于2是因为c在交换前,a和b已经交换了,所以c在和a交换的时候其实是1.001和2交换
而a之所以等于1,是因为在c和a交换后,a为1.001,然后因为a是int类型导致数据丢失
模板参数的匹配原则
template<typename T>
T ADD(const T& left, const T& right)
{return left + right;
}
int ADD(const int& left, const int& right)
{return left + right;
}
int main()
{int a = 1, b = 2;cout << ADD(a, b) << endl;return 0;
}
这段代码可以正常运行,但是现在又一个问题就是两个ADD函数,一个是通用模板,另一个是现成的函数,到底是用的哪一个呢?
显然为偷懒,当然是用现成的函数,所以我们调用的函数是先从的ADD函数
而下面这种就不是调用现成的ADD函数了,因为这里用了显示实例化,也就表示了你必须调用模板函数,让T变成int类型,即使有现成的函数也不可以偷懒
类模板
类模板的定义格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{// 类内成员定义
};
类模板的实例化
来看看下面的例子
template<typename T>
class A
{
public:T ADD(const T& left, const T& right){return left + right;}
private:T a;int b;
};
int main()
{int c = 0, d = 2;double e = 0.0001, f = 1.0001;A <int>a;A<double>b;cout << a.ADD(c, d) << endl;cout << b.ADD(e, f) << endl;return 0;
}
类模版的实例化都是显示实例化,也就是在定义的时候我们就要规定T是什么类型,例如A < int> a表示这a这个对象中T是int类型,其次类中的函数也是和之前的模板函数一样的