我们在C语言阶段写代码的时候,遇到相同的函数,但是传参的类型是不同的类型的时候,我们可能会繁琐的写三个相同的函数,但是这时候我们可以运用C++的模版 ,而模版可以极大的帮助我们简化我们的代码工作量。
泛型编程:使用模板,编写跟类型无关的代码。
比如说我们编写一些函数和类的时候,针对不同类型需要写很多重复的代码。
pg:
函数:比如我们想实现交换int、double、char等等各种类型对象函数swap
类:比如我们想实现一个数据结构栈stack,stack的多个对象 st1存int,st2存double,等等。
在没有模板之前,我们得针对各个类型写很多个swap函数和stack类。而这些函数和类,逻辑是一样的,只是处理的对象类型不同。
模版分为函数模版和类模版:
接下来通过C和C++的代码介绍一下函数模版的优点:
这里是C语言的时候的代码:
//泛型编程 // 模板 void Swap(int& x1, int& x2) { int x = x1; x1 = x2; x2 = x; } void Swap(double& x1, double& x2) { double x = x1; x1 = x2; x2 = x; } void Swap(char& x1, char& x2) { char x = x1; x1 = x2; x2 = x; } int main() { int a = 0, b = 1; double c = 1.1, d = 2.22; Swap(a, b); Swap(c, d); char e = 'A', f = 'B'; Swap(e, f); return 0; }
这里是C++运用函数模版的代码:
// Type // 函数模板 //template<class T1, class T2> // template<typename T> // 模板参数列表 -- 参数类型 template<class T>//也可以写成template<typename T> void Swap(T& x1, T& x2) // 函数参数列表 -- 参数对象 { T x = x1; x1 = x2; x2 = x; } int main() { int a = 0, b = 1; double c = 1.1, d = 2.22; Swap(a, b); Swap(c, d); char e = 'A', f = 'B'; Swap(e, f); return 0; } // 专门处理int的加法函数 int Add(int left, int right) { return left + right; } // 通用加法函数 template<class T1, class T2> T1 Add(T1 left, T2 right) { return left + right; }
ps: 注意要加template<class T>,也可以写成template<typename T>
然后void Swap(T& x1, T& x2),这里需要C++的引用,T是不同的参数类型,这里可以根据不同情况自行选择。
接下来展示一下怎么使用函数模版,这里函数的目的是求两数之和:
template<class T> T Add(const T& left, const T& right) { return left + right; } int main() { int a1 = 10, a2 = 20; double d1 = 10.1, d2 = 20.2; cout << Add(a1, a2) << endl; cout << Add(d1, d2) << endl; cout << Add((double)a1, d2) << endl; // 显示实例化 cout << Add<int>(a1, d2) << endl; cout << Add<double>(a1, d2) << endl; return 0; }
类模版:
那么为什么用C++实现更好呢?
C语言的缺点:
1.忘记初始化和销毁
2.没有封装;谁都可以修改结构体的数据
3.如果想同时定义两个栈,一个栈存int,一个栈都double,做不到
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
public :
Vector(size_t capacity = 10)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
// 使用析构函数演示:在类中声明,在类外定义。
~Vector();
void PushBack(const T& data);
void PopBack();
// ...
size_t Size() {return _size;}
T& operator[](size_t pos)
{
assert(pos < _size);
return _pData[pos];
}
private:
T* _pData;
size_t _size;
size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
if(_pData)
delete[] _pData;
_size = _capacity = 0;
}
模版的原理:编译器根据调用函数模板和类模板的类型,实例化出对应的函数和类
编译器是把实例化生成的函数和类放到进程的代码段去执行