模板
c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板。
凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。c++提供两种模板机制:函数模板和类模1板类属-类型参数化,又称参数模板
函数模板
函数模板的定义
模板关键字template
#include <iostream>
using namespace std;
//T只能对当前函数有效, typename可以换成class
template<typename T> void swapAll(T &a, T &b)
{
T tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10, b = 20;
//函数调用时, 更具实参类型 会自动推导T的类型
swapAll(a, b);
cout << a << " " << b << endl;
char a1 = 'a', b1 = 'b';
swapAll(a1, b1);
cout << a1 << " " << b1 << endl;
return 0;
}
函数模板 会编译两次:
1
对函数模板自身编译
2
函数调用处 将T的类型具体化函数模板目标: 模板是为了实现泛型, 可以减轻编译的工作量, 增强函数的重用性
函数模板的注意点
函数模板和普通函数都识别(优先选择普通函数)
template<class T> void swapAll(T &a, T &b)
{
T tmp = a;
a = b;
b = tmp;
cout << "函数模板" << endl;
}
void swapAll(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
cout << "普通函数" << endl;
}
void main()
{
int a = 10, b = 20;
swapAll(a, b); //调用普通函数
}
函数模板 和 普通函数 都识别. 但强制使用函数模板
int main()
{
int a = 10, b = 20;
//强制使用函数模板
swapAll<>(a, b); //调用函数模板
}
函数模板 自动类型推导 不能对函数的参数进行 自动类型转换
template<class T> void myPrintAll(T a, T b)
{
cout << a << " " << b << endl;
cout << "函数模板" << endl;
}
void myPrintAll(int a, int b)
{
cout << a << " " << b << endl;
cout << "普通函数" << endl;
}
int main()
{
myPrintAll(10, 20); //普通函数
myPrintAll('a', 'b'); //函数模板
myPrintAll(10, 'b'); //普通函数 可以 自动类型转换
//强制说明T为int类型 就支持自动类型转换
myPrintAll<int>(10, 'b');
}
函数模板的重载
template<class T> void myPrintAll(T a)
{
cout << a << endl;
cout << "函数模板" << endl;
}
template<class T> void myPrintAll(T a, T b)
{
cout << a << " " << b << endl;
cout << "函数模板" << endl;
}
函数模板的局限性
当函数模板 推导出T为数组或其他自定义类型数据 可能导致运算符 不识别
解决方法
运算符重载(推荐)
#include <iostream>
using namespace std;
class Data
{
friend ostream& operator<<(ostream& out, Data ob);
private:
int data;
public:
Data(){}
Data(int data)
{
this->data = data;
}
};
ostream& operator<<(ostream& out, Data ob)
{
out << ob.data;
return out;
}
template<class T> void myPrintAll(T a)
{
cout << a << endl;
cout << "函数模板" << endl;
}
int main()
{
myPrintAll(10); //10
myPrintAll('a'); //'a'
Data ob1(100);
myPrintAll(ob1); //100
}
具体化函数模板
#include <iostream>
using namespace std;
template<class T> void myPrintAll(T a)
{
cout << a << endl;
cout << "函数模板" << endl;
}
class Data
{
friend void myPrintAll<Data>(Data ob);
private:
int data;
public:
Data(){}
Data(int data)
{
this->data = data;
}
};
//函数模板具体化
template<> void myPrintAll<Data>(Data ob)
{
cout << ob.data << endl;
cout << "函数模板具体化" << endl;
}
int main()
{
myPrintAll(10);
myPrintAll('a');
Data ob(10);
myPrintAll(ob);
return 0;
}
类模板
类模板基本概念
有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。类模板用于实现类所需数据的类型参数化。
类模板的定义方式
#include <iostream>
using namespace std;
//类模板
template<class T1, class T2> class Data
{
private:
T1 a;
T2 b;
public:
Data(){}
Data(T1 a, T2 b)
{
this->a = a;
this->b = b;
}
void showData()
{
cout << a << " " << b << endl;
}
};
int main()
{
// Data ob; //error 无参推导不出T的类型
Data ob(10, 'c');
Data<int, int> ob2(100, 'c');
ob.showData();
ob2.showData();
return 0;
}
类模板的成员函数在类外实现
#include <iostream>
using namespace std;
template<class T1, class T2>
class Data
{
private:
T1 a;
T2 b;
public:
Data(){}
Data(T1 a, T2 b);
void showData();
};
template<class T1, class T2>Data<T1, T2>::Data(T1 a, T2 b)
{
this->a = a;
this->b = b;
}
template<class T1, class T2>
void Data<T1, T2>::showData()
{
cout << a << " " << b << endl;
}
int main()
{
Data ob(100, 200);
ob.showData();
return 0;
}
函数模板作为类模板的友元
#include <iostream>
using namespace std;
//类模板
template<class T1, class T2>
class Data
{
template<class T3, class T4>
friend void myPrintData(Data<T3, T4> &ob);
private:
T1 a;
T2 b;
public:
Data(){}
Data(T1 a, T2 b);
void showData();
};
//函数模板
template<class T3, class T4>
void myPrintData(Data<T3, T4> &ob)
{
cout << ob.a << " " << ob.b << endl;
}
int main()
{
Data<int, char> ob(100, 'a');
myPrintData(ob);
return 0;
}
template<class T1, class T2>
Data<T1, T2>::Data(T1 a, T2 b)
{
this->a = a;
this->b = b;
}
template<class T1, class T2>
void Data<T1, T2>::showData()
{
cout << a << " " << b << endl;
}
普通函数作为类模板的友元
template<class T1, class T2>
class Data
{
friend void myPrintData(Data<int, char> &ob);
private:
T1 a;
T2 b;
public:
Data(){}
Data(T1 a, T2 b);
void showData();
};
void myPrintData(Data<int, char> &ob)
{
cout << ob.a << " " << ob.b << endl;
}
int main()
{
Data<int, char> ob1(100, 'A');
myPrintData(ob1);
}
模板头文件和源文件分离问题
模板. h文件 和 .cpp文件分离后main.cpp要都include才能运行,比较麻烦, 所以用.hpp包含这两部分
data.hpp
#ifndef DATA_H
#define DATA_H
#include<iostream>
using namespace std;
template<class T1, class T2>
class Data
{
private:
T1 a;
T2 b;
public:
Data();
Data(T1 a, T2 b);
void showData();
};
template<class T1, class T2>Data<T1, T2>::Data()
{
cout << "无参构造" << endl;
}
template<class T1, class T2>Data<T1, T2>::Data(T1 a, T2 b)
{
this->a = a;
this->b = b;
}
template<class T1, class T2>
void Data<T1, T2>::showData()
{
cout << a << " " << b << endl;
}
#endif // DATA_H
main.cpp
#include <iostream>
#include"data.hpp"
using namespace std;
int main()
{
Data ob(100, 2);
ob.showData();
return 0;
}
案例: 设计数组类模板
myarray.hpp
#ifndef MYARRAY_HPP
#define MYARRAY_HPP
#include<iostream>
#include<string.h>
using namespace std;
template<class T>
class MyArray
{
template<class T1>
friend ostream& operator<<(ostream& out, MyArray<T1>& ob);
private:
T *arr;
int size;
int capacity;
public:
MyArray();
MyArray(int capacity);
MyArray(const MyArray &ob);
~MyArray();
MyArray& operator=(MyArray &ob);
void pushBack(T element);
void sortArray();
};
template<class T>
MyArray<T>::MyArray()
{
capacity = 5;
size = 0;
arr = new T[capacity];
memset(arr, 0, sizeof(T)*capacity);
}
template<class T>
MyArray<T>::MyArray(int capacity)
{
this->capacity = capacity;
size = 0;
arr = new T[capacity];
memset(arr, 0, sizeof(T)*capacity);
}
template<class T>
MyArray<T>::MyArray(const MyArray &ob)
{
if(arr != NULL)
{
delete[] arr;
arr = NULL;
}
size = ob.size;
capacity = ob.capacity;
arr = new T[capacity];
memset(arr, 0, sizeof(T)*capacity);
memcpy(arr, ob.arr, sizeof(T)*capacity);
}
template<class T>
MyArray<T>::~MyArray()
{
if(arr != NULL)
{
delete[] arr;
arr = NULL;
}
}
template<class T>
MyArray<T>& MyArray<T>::operator=(MyArray &ob)
{
if(arr != NULL)
{
delete[] arr;
arr = NULL;
}
size = ob.size;
capacity = ob.capacity;
arr = new T[capacity];
memset(arr, 0, sizeof(T)*capacity);
memcpy(arr, ob.arr, sizeof(T)*capacity);
return *this;
}
template<class T>
void MyArray<T>::pushBack(T element)
{
if(size == capacity)
{
capacity = capacity*2;
T *tmp = new T[capacity];
memset(tmp, 0, sizeof(T)*capacity);
if(arr != NULL)
{
memcpy(tmp, arr, sizeof(T)*capacity);
delete[] arr;
}
arr = tmp;
}
arr[size] = element;
size++;
}
template<class T>
void MyArray<T>::sortArray()
{
if(size == 0)
{
cout << "容器没有数据" << endl;
}
else
{
for(int i=0;i<size-1;i++)
{
for(int j=i+1;j<size;j++)
{
if(arr[i] > arr[j])
{
T tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
}
}
template<class T1>
ostream &operator<<(ostream &out, MyArray<T1> &ob)
{
for(int i=0;i<ob.size;i++)
{
out << ob.arr[i] << " ";
}
return out;
}
#endif // MYARRAY_HPP
main.cpp
#include <iostream>
#include"myarray.hpp"
#include<string>
using namespace std;
class Person
{
friend ostream& operator<<(ostream& out, Person& ob);
private:
int num;
string name;
float score;
public:
Person(){}
Person(int num, string name, float score)
{
this->num = num;
this->name = name;
this->score = score;
}
bool operator>(Person& ob)
{
return num>ob.num;
}
};
ostream& operator<<(ostream& out, Person& ob)
{
out << ob.num << " " << ob.name << " " << ob.score;
return out;
}
int main()
{
MyArray<int> arr1;
arr1.pushBack(20);
arr1.pushBack(9);
arr1.pushBack(80);
arr1.pushBack(55);
arr1.pushBack(79);
arr1.pushBack(86);
arr1.pushBack(15);
arr1.pushBack(85);
arr1.pushBack(100);
arr1.pushBack(2);
cout << arr1 << endl;
arr1.sortArray();
cout << arr1 << endl;
MyArray<Person> arr2;
arr2.pushBack(Person(3, "lucy", 98));
arr2.pushBack(Person(1, "back", 45));
arr2.pushBack(Person(7, "jack", 38));
arr2.pushBack(Person(5, "wuh", 99));
arr2.pushBack(Person(9, "lip", 85));
arr2.sortArray();
cout << arr2 << endl;
return 0;
}
类模板的继承
类模板 派生出 普通类
#include <iostream>
using namespace std;
template<class T1, class T2>
class Base
{
private:
T1 a;
T2 b;
public:
Base(){}
Base(T1 a, T2 b);
void showData();
};
template<class T1, class T2>
Base<T1, T2>::Base(T1 a, T2 b)
{
this->a = a;
this->b = b;
}
template<class T1, class T2>
void Base<T1, T2>::showData()
{
cout << a << " " << b << endl;
}
//类模板派生出类模板
template<class T1, class T2, class T3>
class Son1: public Base<T1, T2>
{
public:
T3 c;
public:
Son1(T1 a, T2 b, T3 c): Base<T1, T2>(a, b){
this->c = c;
}
};
int main()
{
Son1<int, char, int> ob1(100, 'A', 200);
ob1.showData();
cout << ob1.c << endl;
return 0;
}
标签:arr,capacity,18,void,template,Data,模板
From: https://www.cnblogs.com/mzx233/p/17757645.html