一.类模板特化
1.为什么需要这个?
类模板特化是一种在C++中提供泛型编程的手段。泛型编程是一种编程范式,让程序员在强类型语言(如C++)环境中编写高度可复用的代码。
让我们首先理解什么是类模板。类模板是一种创建泛型类的工具,它允许程序员创建适应多种数据类型的类,而不需要为每一种数据类型编写一个单独的类。例如,你可以创建一个名为 MyType
的模板类,然后使用 MyType<int>
,MyType<double>
,MyType<std::string>
等来实例化不同类型的对象。
然而,有时候你可能需要对特定类型的模板进行一些特殊的处理。例如,你可能有一个模板类,它在处理整数时需要一个特殊的算法,而在处理其他类型时需要另一个算法。在这种情况下,你可以使用类模板特化。
类模板特化是一种声明一个模板的特殊行为的方式,当模板被特定类型的参数实例化时,这个特殊行为就会发生。例如,你可以特化 MyType<int>
,使其行为与其他类型的 MyType
不同。
总的来说,类模板特化提供了一种在保持代码复用的同时,能够对特定类型进行特殊处理的方法,这是泛型编程中的一个强大工具。
/* 类模板特化.cpp */
//设计一通用数组类,它能够直接存取数组元素,并能够对数组进行从大到小的排序。
#include <cstring>
#include <iostream>
using namespace std;
const int Size = 5;
template <class T> class Array {
private:
T a[Size];
public:
Array() {
for (int i = 0; i < Size; i++) {
a[i] = 0;
}
}
T &operator[](int i);
void Sort();
};
template <class T> T &Array<T>::operator[](int i) {
if (i < 0 || i > Size - 1) {
cout << "\n数组下标越界!" << endl;
exit(1);
}
return a[i];
}
template <class T> void Array<T>::Sort() {
int p;
for (int i = 0; i < Size - 1; i++) {
p = i;
for (int j = i; j < Size; j++) {
if (a[p] < a[j])
p = j;
}
T t = a[p];
a[p] = a[i];
a[i] = t;
}
}
// template <> 返回类型 类模板名<特化的数据类型>::特化成员函数名(参数表){}
template <>
void Array<char *>::Sort() {
int p;
for (int i = 0; i < Size - 1; i++) {
p = i;
for (int j = i + 1; j < Size; j++)
if (strcmp(a[p], a[j]) < 0)
p = j;
char *t = a[p];
a[p] = a[i];
a[i] = t;
}
}
int main() {
Array<int> a1;
Array<char *> b1;
a1[0] = 1;
a1[1] = 23;
a1[2] = 6;
a1[3] = 3;
a1[4] = 9;
a1.Sort();
for (int i = 0; i < 5; i++)
cout << a1[i] << "\t";
cout << endl;
b1[0] = "x1";
b1[1] = "ya";
b1[2] = "ad";
b1[3] = "be";
b1[4] = "bc";
b1.Sort();
for (int i = 0; i < 5; i++)
cout << b1[i] << "\t";
cout << endl;
}
还可以进行参数的强制转换
/* 求最大值.cpp */
// Eg9-2.cpp
#include <iostream>
using namespace std;
template <class T> T Max(T a, T b) { return (a > b) ? a : b; }
/*
C++在实例化函数模板的过程中,只是简单地将模板参数替换成调用实参的类型,并以此生成模板函数,不会进行参数类型的任何转换。
*/
int main() {
double a = 2, b = 3.4;
float c = 5.1, d = 3.2;
//在模板调用时进行参数类型的强制转换
cout << "2, 3.2 的最大值是:" << Max(double(2), 3.2) << endl;
cout << "a, c 的最大值是:" << Max(float(a), c) << endl;
//显示指定函数模板实例化的参数类型
cout << "'a', 3 的最大值是:" << Max<int>('a', 3) << endl;
}
函数模板参数可以是类属参数,也可以包括普通类型的参数
/* 例1.cpp */
//函数模板参数可以是类属参数,也可以包括普通类型的参数
#include <iostream>
using namespace std;
template <class T>
//实现降序
void sort(T *a, int n) {
for (int i = 0; i < n; i++) {
int p = i;
for (int j = i; j < n; j++)
if (a[p] < a[j])
p = j;
T t = a[i];
a[i] = a[p];
a[p] = t;
}
}
template <class T> void display(T &a, int n) {
for (int i = 0; i < n; i++)
cout << a[i] << "\t" << endl;
}
int main(int argc, char const *argv[]) {
int a[] = {1, 41, 2, 5, 8, 21, 23};
char b[] = {'a', 'x', 'y', 'e', 'q', 'g', 'o', 'u'};
sort(a, 7);
sort(b, 8);
display(a, 7);
display(b, 8);
return 0;
}
二.模拟栈
栈是一种线性数据结构,其操作遵循后进先出(LIFO)的原则。这意味着最后一个被添加到栈中的元素将是第一个被移除的元素。
栈具有以下基本操作:
- push(x):将元素x添加到栈的顶部。
- pop:删除栈顶的元素并返回该元素。
- top(x):返回栈顶的元素但不删除。
- empty:检查栈是否为空,返回True或False。
栈在许多算法和程序设计中都有应用,例如在计算机科学中的深度优先搜索,括号匹配,后缀/中缀/前缀表达式的求值,函数调用和递归等场景中。
在日常生活中,我们可以将栈理解为一种累积或者堆积的方式,比如叠盘子,最后放上去的盘子将是第一个被取走的。
/* 模拟栈.cpp */
/*
设计一个堆栈的类模板Stack,在模板中用类型参数T表示栈中存放的数据,用非类型参数MAXSIZE代表栈的大小。
*/
#include <iostream>
using namespace std;
template <class T, int MAXSIZE> class Stack {
private:
T elem[MAXSIZE];
int top;
public:
Stack() { top = 0; };
void push(T e);
T pop();
bool empty() {
if (top <= -1)
return 1;
else
return 0;
}
void setEmpty() { top = -1; }
bool full() {
if (top >= MAXSIZE - 1) {
return 1;
}
else
return 0;
}
};
/*
原型:
template <模板参数列表>
返回值类型 类模板名<模板参数名表>::成员函数名 (参数列表){};
*/
template <class T, int MAXSIZE> void Stack<T, MAXSIZE>::push(T e) {
if (full()) {
cout << "栈已满,不能再添加元素了!";
return;
}
elem[++top] = e;
}
template <class T, int MAXSIZE> T Stack<T, MAXSIZE>::pop() {
if (empty()) {
cout << "栈已空,不能再弹出元素了!" << endl;
return 0;
}
return elem[top--];
}
int main(int argc, char const* argv[]) {
//类模板实例化
Stack<int, 10> iStack;
Stack<char, 10> cStack;
iStack.setEmpty();
cStack.setEmpty();
cout << "-------intStack----\n";
int i;
for (i = 1; i < 11; i++)
iStack.push(i);
for (i = 1; i < 11; i++)
cout << iStack.pop() << "\t";
cout << "\n\n-------charStack----\n";
cStack.push('A');
cStack.push('B');
cStack.push('C');
cStack.push('D');
cStack.push('E');
for (i = 1; i < 6; i++)
cout << cStack.pop() << "\t";
cout << endl;
return 0;
}
三.模板特化
/* 模板特化.cpp */
// Eg9-6.cpp
#include <cstring>
#include <iostream>
using namespace std;
template <class T> T Max(T a, T b) { return (a > b) ? a : b; }
//特化
// template <> 返回类型 函数名<特化的数据类型>(参数表) {}
template <> const char *Max<const char *>(const char *a, const char *b) {
return (strcmp(a, b) >= 0) ? a : b;
}
template <> char *Max<char *>(char *a, char *b) {
return (strcmp(a, b) >= 0) ? a : b;
}
int main() {
float c = 5.1, d = 3.2;
char s1[] = "xyce", s2[] = "xbv";
cout << "2,3的最大值是:" << Max(3, 2) << endl;
cout << "c,d的最大值是:" << Max(c, d) << endl;
cout << Max("xbv", "xyce") << endl;
cout << Max(s1, s2) << endl;
}
/*
① 当程序中同时存在模板和它的特化时,特化将被优先调用;
②
在同一个程序中,除了函数模板和它的特化外,还可以有同名的普通函数。其区别在于C++会对普通函数的调用实参进行隐式的类型转换,
但不会对模板函数及特化函数的参数进行任何形式的类型转换。
*/