模板的概念
- 泛型编程:指的是编写与类型无关的逻辑代码,在泛型编程中,编写的代码可以作用多种类型的对象
- 模板:就是实现代码重用的一种工具,它可以实现类型参数化,即把类型定义为参数,从而实现了代码的重用性。模板就是泛型编程的基础
- 模板分类:函数模板、类模板
函数模板
函数模板:函数模板不是一个实体函数,编译器不会对一个函数模板生成可执行代码。定义函数模板之后只是说对一个函数功能框架的一个描述。只有在调用的时候才会为其生成可执行代码
函数模板和模板函数的区别:
- 函数模板:是模板,函数的模板
- 模板函数:函数,通过函数的模板产生的一个函数
函数模板的定义
- template 关键字,表示模板
- <>表示类型参数列表,类似函数的参数列表,只不过类型参数列表中的参数为类型参数
- typename 类型名(还有一个修饰类型的关键叫 class)
#include<iostream>
template<typename T>
T myAdd(T a, T b)
{
return a + b;
}
template<class T1>
T1 mySub(T1 a, T1 b)
{
return a - b;
}
void main()
{
printf("%d\n", myAdd(1, 2));
printf("%f\n", myAdd(1.1f, 2.3f));
}
template<class T>
T mydev(T a, T b)
{
return a / b;
}

观察以上代码,T mydev(T a, T b)是在main函数后,但是运行成功,体现了只有在调用的时候才会为其生成可执行代码这个特性。当把T mydev(T a, T b)函数中的分号去掉时也不会报错,只有在调用时才会报错。
隐式推导和显示推导:
- 观察以下报错,报错原因:1是整型,1.2是浮点型,这样是无法推导出模板的T类型,只能用显示推导


模板与模板可以重载,模板与普通函数可以重载:
- 模板和模板进行重载只需要函数名相同,参数列表不同(函数的参数列表或者是模板的类型参数列表)
- 调用函数,优先匹配参数完全吻合的普通函数,匹配不上,再匹配函数模板,如果还匹配不上,再匹配能否经过强转执行普通函数

不能对结构体进行相加,若想相加必须重载运算符:
(除通用性操作(排序、数组的增删改查等)需要模板,大部分情况不需要用模板)

类模板
类模板:是一个类类型的样板,不能直接使用
模板类:通过类模板生成的一个具体类型的类类型
以下是类模板的一个代码示例:
#include<iostream>
template<typename T>
class MyArr
{
T *pArr;
int len;
int maxSize;
public:
MyArr()
{
pArr = NULL;
len = maxSize = 0;
}
~MyArr()
{
if (pArr)
delete[] pArr;
pArr = NULL;
}
void setMaxSize(int m)
{
maxSize = m;
}
bool insert(int index, T const& data)
{
if (index < 0 || index >= maxSize)
return false;
if (pArr == NULL)
pArr = new T[maxSize];
if (index > len)
{
pArr[len++] = data;
}
else
{
for (int i = len; i > index; --i)
{
pArr[i] = pArr[i - 1];
}
pArr[index] = data;
len++;
}
return true;
}
};
void main()
{
//函数有参数列表,可以推导类型参数,类没有参数列表,只能显示表示模板类
MyArr<int> m;
m.setMaxSize(10);
m.insert(5, 100);
m.insert(0, 101);
}

类模板不分文件编写
-
先用文件编写的方式创建一个类

-
在头文件中编写类模板

-
在.cpp文件中发现类的构造和析构是不合法的

-
原因:因为在模板编译时不会生成可执行代码,所以虽然text是类名,但是现在还没有类,只有模板。而我们在分文件编写中提到,所有不产生内存的都写在.h文件中,.cpp文件是需要写带内存的东西。所以我们可以改为以下形式:

-
在主函数中调用:

类模板写一个栈
- 创建一个stack.h头文件,并写入栈结构
#pragma once
template<class T, int maxSize>
class CMyStack //栈结构
{
T stackArr[maxSize];
int top;
public:
CMyStack();
~CMyStack();
void push(T const& data); //入栈
void pop(); //出栈
T getTop() const; //得到栈顶元素
};
template<class T, int maxSize>
T CMyStack<T, maxSize>::getTop() const
{
return stackArr[top - 1];
}
template<class T, int maxSize>
void CMyStack<T, maxSize>::pop()
{
top--;
}
template<class T, int maxSize>
void CMyStack<T, maxSize>::push(T const& data)
{
stackArr[top++] = data;
}
template <class T, int maxSize>
CMyStack<T, maxSize>::CMyStack()
{
top = 0;
}
template <class T, int maxSize>
CMyStack<T, maxSize>::~CMyStack()
{
}
- 在主函数中运行

类模板中的一些特殊情况
template <class T, int val>
class CA
{
T arr[val];
};
template<class T1>
void fun1(CA<T1, 10> & a){} //函数是模板,且把模板参数给到函数自己的参数中的类模板
template<class T1, class T2>
void fun2(CA<T1, 20> & a) //函数是模板,且模板参数分两类,一类给到自己函数体用,一类给到参数中的类模板用
{
T2 val;
}
- 基类是模板,派生类也是模板
class CX
{
};
template<class T>
class CY : public CX
{
};

被折叠的 条评论
为什么被折叠?



