其实就是其他语言里的 泛型,函数模板的声明要放在具体实现函数的上方
#include
using namespace std;
void swap_int(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
void swap_double(double& a, double& b) {
double temp = a;
a = b;
b = temp;
}
//函数模板--- typename可以替换成class 即 template 效果一样
template<typename T>//声明一个模板,告诉编译器后面代码中的T不要报错,代表一个通用类型
void swap_T(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
template<class T>
void mySort(T arr[] ,int len)
{
for (int i = 0; i < len; i++)
{
int max = i;
for (int j = i+1; j < len; j++)
{
if (arr[max]<arr[j])
{
max = j;
}
}
if (max!=i)
{
T temp = arr[max];
arr[max] = arr[i];
arr[i] = temp;
}
}
}
void test01()
{
//测试char数组
char charArr[] = "bdace";
mySort(charArr, sizeof(charArr) / sizeof(char));
}
void test02()
{
//测试int数组
int intArr[] = {2,1,4,5,6,7,8,2};
mySort(intArr, sizeof(intArr) / sizeof(int));
}
int main() {
int a = 10, b = 20;
//swap_int(a, b);
//1、自动类型推导
swap_T(a, b);//用模板的好处就是类型可以不指定
cout << "a=" << a << endl;
//2、显示指定类型
swap_T<int>(a, b);
cout << "a=" << a << endl;
system("pause");
return 0;
}
(1)普通函数调用时可以发生自动类型转换(隐式类型转换–如’a’转为 ASCII的 99)
(2)函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
(3)如果利用显示指定类型的方式,可以发生隐式类型转换
如果T的数据类型传入的是自定义类型,会无法正常运行,为了解决这种问题,C++提供了模板的重载,可以为这些特定的类型 提供 具体的模板。
template<class T>
bool myCompare(T& p1, T& p2)
{
if (a==b)
{
return true;
}
else
{
return false;
}
}
//利用具体化Person的版本实现代码,具体化优先调用
template<>bool myCompare(Person &p1,Person&p2)
{
if (p1.name==p2.name&&p1.age==p2.age)
{
return true;
}
else
{
return false;
}
}
建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表
template<typename NameType,class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
m_Name = name;
m_Age = age;
}
NameType m_Name;
AgeType m_Age;
void show()
{
cout << "name:" + m_Name << " age:" << m_Age << endl;
}
};
void test001()
{
Person<string, int>p1("小明",99);
p1.show();
}
1、类模板没有自动类型推导的使用方式
2、类模板在模板参数列表可以有默认函数
1、普通类中的成员函数一开始就可以创建
2、类模板中的成员函数在调用时才创建
一共有三种传入方式:
1、指定传入的类型 – 直接显示对象的数据类型 – 比较常用
2、参数模板化 – 将对象中的参数变为模板进行传递
3、整个类模板化 – 将这个对象类型 模板化进行传递
#include
using namespace std;
#include
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age)
{
this->m_age = age;
this->m_name = name;
}
void showPerson()
{
cout << "姓名:" << this->m_name << "_年龄:" << this->m_age << endl;
}
T1 m_name;
T2 m_age;
};
//1.指定传入类型 -- 最常用
void printPerson1(Person<string, int >& p)
{
p.showPerson();
}
void test0001()
{
Person<string, int >p("小明1", 18);
printPerson1(p);
}
//2.参数模板化
template<class T1,class T2>
void printPerson2(Person<T1, T2 >& p)
{
p.showPerson();
cout << "T1的类型为:" << typeid(T1).name() << endl;
cout << "T2的类型为:" << typeid(T2).name() << endl;
}
void test0002()
{
Person<string, int >p("小明2", 18);
printPerson2(p);
}
//3.整个类模板化
template<class T>
void printPerson3(T &p)
{
p.showPerson();
cout << "T的类型为:" << typeid(T).name() << endl;
}
void test0003()
{
Person<string, int >p("小明3", 18);
printPerson3(p);
}
int main() {
test0001();
test0002();
test0003();
system("pause");
return 0;
}
//类模板与继承
template<class T>
class Base
{
T m;
};
//class Son :public Base //错误,必须知道父类中的 T 类型,才能继承给子类
class Son :public Base<int>
{
};
void test004()
{
Son s1;
}
//如果想灵活指定父类中T类型,子类也需要变类模板
template<class T1,class T2>
class Son2 :public Base<T1>
{
public:
Son2()
{
cout << "T1的类型为:" << typeid(T1).name() << endl;
cout << "T2的类型为:" << typeid(T2).name() << endl;
}
T2 obj;
};
void test005()
{
Son2<int, char>s2;
}
案例.hpp
//自己通用的数组类
// MyArray.hpp
#pragma once
#include
using namespace std;
template<class T>
class MyArray
{
public:
//有参构造 参数 容量
MyArray(int capacity)
{
//cout << "MyArray有参构造" << endl;
this->m_Capacity = capacity;
this->m_Size = 0;
this->pAddress = new T[this->m_Capacity];
}
//拷贝构造
MyArray(const MyArray& arr)
{
//cout << "MyArray拷贝构造" << endl;
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
//深拷贝
this->pAddress = new T[arr.m_Capacity];
//将arr中的数据都拷贝过来
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
}
//operator= 防止浅拷贝问题
MyArray& operator=(const MyArray& arr)
{
//cout << "MyArray 的operator=调用 " << endl;
//先判断原来堆区是否有数据 如果有先释放
if (this->pAddress != NULL)
{
delete[] this->pAddress;
this->pAddress = NULL;
this->m_Capacity = 0;
this->m_Size = 0;
}
//深拷贝
this->m_Capacity = arr.m_Capacity;
this->m_Size = arr.m_Size;
this->pAddress = new T[m_Capacity];
for (int i = 0; i < this->m_Size; i++)
{
this->pAddress[i] = arr.pAddress[i];
}
return *this;
}
//尾插法
void push_Back(const T& val)
{
//判断容量是否等于大小
if (this->m_Capacity==this->m_Size)
{
return;//容量满了
}
this->pAddress[this->m_Size] = val;//在数组末尾插入数据
this->m_Size++;//更新数组大小
}
//尾删法
void pop_Back()
{
if (this->m_Size==0)
{
return;
}
this->m_Size--;
}
//通过下标方式访问数组中的元素
T& operator[](int index)
{
return this->pAddress[index];
}
//返回数组容量
int getCapacity()
{
return this->m_Capacity;
}
//返回数组大小
int getSize()
{
return this->m_Size;
}
//析构函数
~MyArray()
{
//cout << "MyArray析构构造" << endl;
if (this->pAddress != NULL)
{
delete[] pAddress;
this->pAddress = NULL;
}
}
private:
T* pAddress;//指针指向堆区开辟的真实数组
int m_Capacity;//数组的容量
int m_Size;//数组大小
};
案例.cpp
#include
#include"MyArray.hpp"
using namespace std;
void printIntArray(MyArray<int>& arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << arr[i] << endl;
}
}
void t1()
{
MyArray<int>arr1(5);
for (int i = 0; i < 5; i++)
{
arr1.push_Back(i);
}
cout << "arr1的打印输出为:" << endl;
printIntArray(arr1);
cout << "arr1的容量为:" << arr1.getCapacity() << endl;
cout << "arr1的大小为:" << arr1.getSize() << endl;
MyArray<int>arr2(arr1);
cout << "arr2的打印输出为:" << endl;
printIntArray(arr2);
//尾删
arr2.pop_Back();
cout << "arr2尾删后容量:" << arr2.getCapacity() << " 大小:" << arr2.getSize() << endl;
}
class Per
{
public:
Per() {}
Per(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void printPer(MyArray<Per>& arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << "姓名:" << arr[i].m_Name << "_年龄:" << arr[i].m_Age << endl;
}
}
void t2()
{
MyArray<Per>arr(10);
Per p1("A", 10);
Per p2("B", 11);
Per p3("C", 12);
//将数据插入到数组中
arr.push_Back(p1);
arr.push_Back(p2);
arr.push_Back(p3);
printPer(arr);
cout << "per_arr容量:" << arr.getCapacity() << "_大小:" << arr.getSize();
}
int main()
{
t1();
t2();
system("pause");
return 0;
}
#include
using namespace std;
#include
#include
//vector容器存放 自定义数据类型
class Person2
{
public:
Person2(string name, int age)
{
m_name = name; m_age = age;
}
string m_name;
int m_age;
};
void tt2()
{
vector<Person2>v;
Person2 p1("a", 10);
Person2 p2("b", 11);
v.push_back(p1);
v.push_back(p2);
for (int i = 0; i < v.size(); i++)
{
cout << v[i].m_name << endl;
}
for (vector<Person2>::iterator it = v.begin(); it!=v.end(); it++)
{
cout << it->m_name << endl;
cout << (*it).m_age << endl;
}
}
void myPrint(int val)
{
cout << val << endl;
}
//vector容器存放 int
void tt1()
{
//创建了一个vector容器,数组
vector<int>v;
//向容器中插入数据
v.push_back(10);
v.push_back(20);
//通过迭代器访问容器中的数据
vector<int>::iterator itBegin = v.begin();//起始迭代器 指向容器中第一个元素
vector<int>::iterator itEnd = v.end();//起始迭代器 指向容器中最后一个元素的下一个位置
//第一种遍历方式
while (itBegin != itEnd)
{
cout << *itBegin << endl;
itBegin++;
}
//第二种遍历方式
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
//第三种遍历方式 利用STL提供遍历算法
for_each(v.begin(), v.end(), myPrint);
}
//容器嵌套容器
void ttt1()
{
vector<vector<int>>v;
//创建小容器
vector<int>v1;
vector<int>v2;
vector<int>v3;
//向小容器添加数据
for (int i = 0; i < 3; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
}
//将小容器插入到大容器种
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
//通过大容器,把所有数据遍历一遍
for (vector<vector<int>>::iterator it = v.begin(); it !=v.end(); it++)
{
for (vector<int>::iterator itt = (*it).begin(); itt != (*it).end(); itt++)
{
cout << (*itt) << " ";
}
cout << endl;
}
}
string、vector、deque、
stack、queue、list、set/multiset、map/multimap
案例2:
#include
using namespace std;
#include
#include
#include
#define CEHUA 0
#define MEISHU 1
#define YANFA 2
class Worker
{
public:
string m_Name;//姓名
int m_Salary;//工资
};
void createWorker(vector<Worker>& v_worker)
{
string nameSeed = "ABCDEFGHIJ";
for (int i = 0; i < nameSeed.size(); i++)
{
Worker w;
w.m_Name = "员工";
w.m_Name += nameSeed[i];
w.m_Salary = rand() % 10000 + 10000;//10000~19999
v_worker.push_back(w);
}
}
void SetWorker(vector<Worker>& v, multimap<int, Worker>& m)
{
for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++)
{
int depId = rand() % 3;//0,1,2
//key部门编号,value具体员工
m.insert(make_pair(depId, *(it)));
}
}
void showGroup(multimap<int, Worker>& m)
{
cout << "策划部门:" << endl;
multimap<int, Worker>::iterator pos = m.find(CEHUA);
int count = m.count(CEHUA);
int index = 0;
for (; pos != m.end() && index < count; pos++, index++)
{
cout << "姓名:" << (*pos).second.m_Name << "_薪酬:" << (*pos).second.m_Salary << endl;
}
}
int main()
{
vector<Worker>vWorker;
//1、创建员工
createWorker(vWorker);
for (vector<Worker>::iterator it = vWorker.begin(); it != vWorker.end(); it++)
{
cout << "姓名:" << (*it).m_Name << "_薪酬:" << (*it).m_Salary << endl;
}
//2、员工分组
multimap<int, Worker>mWorker;
SetWorker(vWorker, mWorker);
//3、分组显示
showGroup(mWorker);
system("pause");
return 0;
}
遍历:for_each transform
查找:find find_if adjacent_find binary_search count count_if
排序:
拷贝替换:
算术生成:
#include
集合: