泛型(Generic Programming)即是指具有在多种数据类型上皆可操作的含意。泛型编程的代表作品 STL 是一种高效、泛型、可交互操作的软件组件。
泛型编程初诞生于C++中,目的是为了实现C++的STL(标准模板库)。 其语言支持机制就是模板(Templates)
模板的精神其实很简单:参数化类型。 换句话说, 把一个原本特定于某个类型的算法或类当中的类型信息抽掉,抽出来 做成模板参数 T
所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。
函数模板
template 是语义是模板的意思,尖括号中先写关键字 typename 或是 class ,后面跟一个类型 T,此类即是虚拟的类型。至于为什么用 T,用的人多了,也就是 T 了。
调用过程是这样的,先将函数模板实在化为函数,然后再发生函数调用
函数模板,只适用于函数的参数个数相同 而 类型不同 ,且 函数体相同的情况。 如果个数不同,则不能用函数模板。
普通函数会进行隐士的数据类型转换,
函数模板不提供隐式的数据类型转换, 必须是严格的匹配。
函数模板可以像普通函数那样都可以被重载
编译器对模板机制剖析
类模板
类模板与函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,所以将类中的类型进行泛化。
模板类的派生
类模板实现
函数体写在类中
函数体写在类外
使用这个类模板,需要前面要加上面红框内的,声明,所以不要滥用友元,非常麻烦
friend Complex< T > mySub < T > (Complex< T > &one,Complex< T> &another)
综上: 模板类不要轻易使用友元函数。
类模板中的static
例子:实现一个模板数组类
#include<iostream>
using namespace std;
template<class T>
class MyArray{
public:
MyArray<T> (int capacity){
this->mCapacity = capacity;
this->mSize = 0;
//申请内存
this->pAddr = new T[this->mCapacity];
}
MyArray<T> (const MyArray<T>& arr){
this->mSize = arr.mSize;
this->mCapacity = arr.mCapacity;
//申请内存空间
this->pAddr = new T[this->mCapacity];
//数据拷贝
for (int i = 0; i < this->mSize; i++){
this->pAddr[i] = arr.pAddr[i];
}
}
T& operator[](int index){
return this->pAddr[index];
}
MyArray<T>& operator=(const MyArray<T>& arr){
if (this->pAddr != NULL){
delete[] this->pAddr;
}
this->mSize = arr.mSize;
this->mCapacity = arr.mCapacity;
//申请内存空间
this->pAddr = new T[this->mCapacity];
//数据拷贝
for (int i = 0; i < this->mSize; i++){
this->pAddr[i] = arr.pAddr[i];
}
return *this;
}
void PushBack(T& data){
//判断容器中是否有位置
if (this->mSize >= this->mCapacity){
return;
}
//调用拷贝构造 =号操作符
//1. 对象元素必须能够被拷贝
//2. 容器都是值寓意,而非引用寓意 向容器中放入元素,都是放入的元素的拷贝份
//3 如果元素的成员有指针,注意深拷贝和浅拷贝问题
this->pAddr[this->mSize] = data;
//msize++
this->mSize++;
}
//右值引用 类型 &&a =右值表达式
//T&& 对右值取引用
void PushBack(T&& data){
//判断容器中是否有位置
if (this->mSize >= this->mCapacity){
return;
}
this->pAddr[this->mSize] = data;
//msize++
this->mSize++;
}
~MyArray(){
if (this->pAddr != NULL){
delete[] this->pAddr;
}
}
public:
//一共可以容下多少个元素
int mCapacity;
//当前数组有多少元素
int mSize;
//保存数据的首地址
T* pAddr;
};
void test01(){
MyArray<int> marray(20);
int a = 10, b = 20, c = 30, d = 40;
marray.PushBack(a);
marray.PushBack(b);
marray.PushBack(c);
marray.PushBack(d);
//不能对右值取引用
//左值 可以在多行使用
//右值 临时变量 只能当前行使用
marray.PushBack(100);
marray.PushBack(200);
marray.PushBack(300);
for (int i = 0; i < marray.mSize; i++){
cout << marray[i] << " ";
}
cout << endl;
}
class Person {
friend ostream& operator<<(ostream& os, Person& person) {
os << "Age:" << person.mAge << " " << "Id:" << person.mId << endl;
return os;
}
public:
Person() {
this->mAge = 0;
this->mId = 0;
}
Person(int age,int id) {
this->mAge = age;
this->mId = id;
}
public:
int mAge;
int mId;
};
void test02(){
Person p1(10,20), p2(30,40);
MyArray<Person> arr(10);
arr.PushBack(p1);
arr.PushBack(p2);
for (int i = 0; i < arr.mSize; i++) {
cout << arr[i];
}
cout << endl;
}
int main(){
//test01();
test02();
return 0;
}