C++模板
模板编程也叫泛型编程,忽略数据类型的一种编程
template<class Type1,class Type2,...>
// class 和typename效果一样的
总体介绍
- 学会模板基本
- 函数模板
- 类模板
- 标准中模板类(STL)
- 容器—>数据结构
- 迭代器—>遍历容器
- 仿函数—>描述关系
- 算法—>各种基本算法
简单模板
#include<iostream>
#include<string>
using namespace std;
//int Max(int a, int b)
//{
// return a > b ? a : b;
//}
//string Max(string a, string b) {
// return a > b ? a : b;
//}
//double Max(double a, double b) {
// return a > b ? a : b;
//}
template<class Type> // template <typename Type>等效的
Type Max(Type a, Type b) {
return a > b ? a : b;
}
int main() {
cout << Max(string("yxc"), string("xc")) << endl; // Type = string
cout << Max(1, 2) << endl; // Type = int
return 0;
}
函数模板
- 两个模板都能使用,优先调用未知类型少
- 显示调用百分百调用函数模板
- 隐式调用 优先调用匹配到的普通函数
#include<iostream>
#include<string>
using namespace std;
// No.1模板的调用过程
// 一般情况 自己想要用到几个未知类型就定义几个
template<class _Ty1,class _Ty2,class _Ty3>
void print(_Ty1 one, _Ty2 two, _Ty3 three)
{
cout << "print:" << endl;
cout << one << endl; // _Ty1=YXC cout<<yxcObject<<endl;
cout << two << endl;
cout << three << endl;
}
void testCall()
{
cout << "testCall:" << endl;
// 隐式调用
// 常量的自动推断是: const char*
print(string("123"), 1, 1.1); // 自动推断类型 _Ty1=string _Ty2=int _Ty3=dboule
// 显示调用:传入的类型需要和数据保持一致
// 函数名<传入类型>(参数)
print<double, double, double>(1.11, 2.22, 3);
// print<double,double,double>(1.11,2.22,string("yxcyxc"));
print<string, int, string>(string("string"), 1, string("yxc"));
}
// No.2 函数模板操作自定义类型
class YXC
{
public:
YXC(string name,int age):name(name),age(age){}
friend ostream& operator<<(ostream& out, const YXC& object) {
out << object.name << "\t" << object.age;
return out;
}
protected:
string name;
int age;
};
void testUserData()
{
cout << endl << endl;
cout << "testUserData:"<<endl;
// 使用别人的模板,最大的问题就是重载
YXC object("yxc", 20);
print(object, 1, 2);
}
// No.3 函数模板的另一个形态
class Boy
{
public:
template<typename _Ty1>
void print(_Ty1 one);
protected:
};
template <typename _Ty1> void Boy::print(_Ty1 one)
{
cout << one << endl;
}
void classFunc() {
cout << endl;
cout << "classFunc:" << endl;
Boy boy;
boy.print("yxcYYDS");
}
// No.4 函数模板的重载
// 思考问题的隐式调用调用是哪个函数
template <typename _Ty1,typename _Ty2>
void printData(_Ty1 one, _Ty2 two) {
cout << "两个未知类型" << endl;
cout << one << endl;
cout << two << endl;
}
template <class _Ty1>
void printData(_Ty1 one, _Ty1 two)
{
cout << "一个未知类型" << endl;
cout << one << endl;
cout << two << endl;
}
template <typename _Ty1>
void printData(_Ty1 one)
{
cout << "一个:" << endl;
cout << one << endl;
}
void printData(int data)
{
cout << "普通函数" << endl;
cout << data << endl;
}
void testFunc()
{
cout << endl << endl;
cout << "testFunc:";
printData(1, 2); // 两个模板都能使用,优先调用未知类型少的那个
printData(1, string("2")); // 只适用于第一个
printData<int>(1); // 显示调用百分百调用函数模板
printData(22); // 隐式调用 优先调用匹配到的普通函数
}
// No.5 函数模板也是传参,所以也可以缺省
template<class _Ty1=int>
void printNum(_Ty1 one)
{
cout << one << endl;
}
void testCallNum() {
cout << endl << endl;
cout << "testCallNum:";
printNum(1);
printNum(1.11);
printNum(string("yxc"));
printNum<>(2333);
printNum<string>(string("string"));
}
// No.6 模板含变量情况
template <class _Ty1,size_t size>
void NewMemory(_Ty1*& p)
{
p = new _Ty1[size];
}
void testNew()
{
cout << endl << endl;
cout << "testNew:";
int* p = nullptr;
NewMemory<int, 3>(p);
p[0] = 1;
cout << p[0];
char* pstr = nullptr;
NewMemory<char,10>(pstr);
strcpy_s(pstr, 10, "ILoveyou");
cout << pstr << endl;
// 错误写法,只能传入常量
// const int size = 10;
// int* pp = nullptr;
// NewMemory<int,size>(pstr);
}
int main()
{
testCall();
testUserData();
classFunc();
testFunc();
testCallNum();
testNew();
return 0;
}
类模板
- 类模板不是一个完整类,所有用到类型的地方,必须要 :类名<未知类型>
- 类模板必须要用显示调用方式,不能隐式
- 多文件中类模板不能分开写,必须写在一个文件中 ,xxx.hpp
#include<iostream>
#include<array>
using namespace std;
// 类模板
// No.1 类模板的写法
// 1.1类模板不是一个完整的类,所有用到类型的地方,必须要:类名<未知类型>
// 2.2类模板必须要用显示调用的方式,不能隐式
// 2.3多文件中类模板不能分开写,必须写在一个文件中,xxx.hpp
template <class _Ty1,class _Ty2>
struct my_pair
{
_Ty1 first;
_Ty2 second;
my_pair(_Ty1 first, _Ty2 second);
void print()
{
cout << first << endl;
cout << second << endl;
}
};
template <class _Ty1,class _Ty2>
my_pair<_Ty1, _Ty2>::my_pair(_Ty1 first,_Ty2 second):first(first),second(second)
{
cout << "所有用到类型的地方都要用类型<未知类型>" << endl;
}
template <class _Ty1>
class YXC
{
public:
YXC(_Ty1 data):data(data){}
protected:
_Ty1 data;
};
template <class _Ty1>
class Boy :public YXC<_Ty1>
{
public:
Boy(_Ty1 data):YXC<_Ty1>(data){}
protected:
};
// No.2 模板类中的静态数据成员
template <class _Ty1>
class Test
{
public:
static int data;
};
template <class _Ty1>
int Test<_Ty1>::data = 123;
// Noo.3 类模板也可以传入变量
template <class _Ty,size_t length>
class my_vector
{
public:
my_vector()
{
max = length;
pData = new _Ty[length];
curSize = 0;
}
void push_back(_Ty data)
{
pData[curSize++] = data;
}
int size() const
{
return max;
}
_Ty& operator[](int index)
{
if (index < 0 || index >= max)
{
throw "length_error";
}
return pData[index];
}
protected:
_Ty* pData;
int curSize;
int max;
};
void test_array()
{
my_vector<int, 5> array;
for (int i = 0; i < array.size(); i++)
{
array.push_back(i);
}
for (int i=0;i<array.size();i++)
{
cout << array[i] << "\t";
}
cout << endl;
}
// No.4 类模板的特化问题
template<class _Ty1,class _Ty2>
class Data
{
public:
Data(_Ty1 one, _Ty2 two):one(one),two(two)
{
cout << "原生模板" << endl;
}
protected:
_Ty1 one;
_Ty2 two;
};
// 局部特化-->特殊化处理
template<class _Ty>
class Data<_Ty, _Ty>
{
public:
Data(_Ty one, _Ty two) :one(one), two(two)
{
cout << "局部特化" << endl;
}
protected:
_Ty one;
_Ty two;
};
// 完全特化-->类型具象化
// 为了`针对特定数据做特定处理
template<>
class Data<int, string>
{
public:
Data(int one, string two) :one(one), two(two)
{
cout << "完全特化" << endl;
}
protected:
int one;
string two;
};
void testData()
{
Data<int, int > data1(1, 1);
Data<int, string> data2(1, string("yxc"));
Data<string, int> data3(string("yxcyxc"), 23333);
}
int main() {
my_pair<int, string> object(1, string("模板"));
object.print();
my_pair<int, string>* p = new my_pair<int, string>(2, string("YXCYXC"));
p->print();
Boy<int> boy(1);
cout << Test<int>::data << endl;
test_array();
testData();
return 0;
}
类模板的嵌套
#include<iostream>
using namespace std;
template <class _Ty1,class _Ty2>
class Test
{
public:
Test()
{
cout << "Test默认无参构造函数1" << endl;
cout << one << " " << two << " " << endl;
}
Test(_Ty1 one, _Ty2 two) : one(one), two(two)
{
cout << "Test有参构造函数1" << endl;
cout << one << " " << two << " " << endl;
}
friend ostream& operator<<(ostream& out, Test& object)
{
out << object.one << endl;
out << object.two << endl;
return out;
}
protected:
_Ty1 one;
_Ty2 two;
};
template<class _Ty1,class _Ty2,class _Ty3>
class Data
{
public:
Data()
{
cout << "Data默认无参构造函数2" << endl;
cout << one << " " << two << " " << three << endl;
};
Data(_Ty1 one, _Ty2 two, _Ty3 three) :one(one), two(two), three(three)
{
cout << "Data有参构造函数2" << endl;
cout << one << " " << two << " " << three << endl;
}
friend ostream& operator<<(ostream& out, Data& object)
{
out << object.one << endl;
out << object.two << endl;
out << object.three << endl;
return out;
}
protected:
_Ty1 one;
_Ty2 two;
_Ty3 three;
};
int main()
{
Data<Test<int,int>,Test<string,string>,Test<int,string>> data1;
cout << "-----------------------" << endl;
Data<Test<int, int>, Test<string, string>, Test<int, string>>
data11(Test<int,int>(1,2),Test<string,string>("YXC","yxc"),Test<int,string>(1,"xc"));
cout << "-----------------------" << endl;
Data<Test<int, Data<int, int, int>>, int, string> data2;
cout << "-----------------------" << endl;
Data<Test<int, Data<int, int, int>>, int, string>
data22(Test<int, Data<int, int, int>>(1, Data<int, int, int>(1, 1, 1)), 1, "yxcYYDS");
cout << "-----------------------" << endl;
// 简化:起别名的方式
using Type1 = Test<int, int>;
using Type2 = Test<string, string>;
using Type3 = Test<int, string>;
Data<Type1, Type2, Type3> usingData11(Type1(1, 2), Type2("YXC", "yxc"), Type3(1, "yxcYYDS"));
return 0;
}
封装模板链表
- 直接上代码
#include<iostream>
#include<string>
#include<list>
using namespace std;
template <class _Ty>
struct Node
{
_Ty data;
Node<_Ty>* next;
Node(_Ty data) :data(data),next(nullptr){}
};
template <class _Ty>
class List
{
public:
List();
void push_back(_Ty data);
void push_front(_Ty data);
void pop_back();
void pop_front();
int size() const;
bool empty() const;
_Ty front() const;
_Ty back() const;
void printList();
Node<_Ty>* begin()
{
return frontNode;
}
Node<_Ty>* end()
{
return nullptr;
}
public:
// 类中类访问数据
class iterator
{
public:
void operator=(Node<_Ty>* pmove)
{
this->pmove = pmove;
}
bool operator!=(Node<_Ty>* pmove)
{
return this->pmove != pmove;
}
void operator++()
{
pmove = pmove->next;
}
_Ty operator*()
{
return pmove->data;
}
protected:
Node<_Ty>* pmove;
};
protected:
Node<_Ty>* frontNode;
Node<_Ty>* backNode;
int curSize;
};
template<class _Ty>
List<_Ty>::List()
{
frontNode = nullptr;
backNode = nullptr;
curSize = 0;
}
template<class _Ty>
inline void List<_Ty>::push_back(_Ty data)
{
Node<_Ty>* newNode = new Node<_Ty>(data);
if (curSize == 0)
{
frontNode = newNode;
// backNode = newNode
}
else
{
backNode->next = newNode;
// backNode = newNode;
}
backNode = newNode;
curSize++;
}
template<class _Ty>
inline void List<_Ty>::push_front(_Ty data)
{
Node<_Ty>* newNode = new Node < _Ty>(data);
if (curSize == 0)
{
// fontNode = newNode;
backNode = newNode;
}
else
{
newNode->next = frontNode;
// frontNode = newNode;
}
frontNode = newNode;
curSize++;
}
template<class _Ty>
inline void List<_Ty>::pop_back()
{
if (curSize == 1)
{
delete frontNode;
frontNode = nullptr;
backNode = nullptr;
}
else
{
Node<_Ty>* pmove = frontNode;
while (pmove->next->next != nullptr)
{
pmove = pmove->next;
}
delete pmove->next; // ==delete backNode;
pmove->next = nullptr;
backNode = pmove;
}
curSize--;
}
template<class _Ty>
inline void List<_Ty>::pop_front()
{
if (curSize == 1)
{
delete frontNode;
frontNode = nullptr;
backNode = nullptr;
}
else
{
Node<_Ty> nextNode = frontNode->next;
delete frontNode;
frontNode = nextNode;
}
curSize--;
}
template<class _Ty>
inline int List<_Ty>::size() const
{
return curSize;
}
template<class _Ty>
inline bool List<_Ty>::empty() const
{
return curSize == 0;
}
template<class _Ty>
inline _Ty List<_Ty>::front() const
{
return frontNode->data;
}
template<class _Ty>
inline _Ty List<_Ty>::back() const
{
return backNode->data;
}
template<class _Ty>
inline void List<_Ty>::printList()
{
Node<_Ty>* pmove = frontNode;
while (pmove != nullptr)
{
cout << pmove->data;
pmove = pmove->next;
}
cout << endl;
}
class YXC
{
public:
YXC(string name,int age) :name(name),age(age){}
friend ostream& operator<<(ostream& out, const YXC& object)
{
out << object.name << "\t" << object.age << endl;
return out;
}
protected:
string name;
int age;
};
int main()
{
List<int> iList;
iList.push_back(1);
iList.push_back(2);
iList.push_front(3);
iList.printList();
iList.pop_back();
iList.printList();
iList.push_back(2);
// 通过类中类打印数据
List<int>::iterator iteri;
for (iteri = iList.begin(); iteri != iList.end(); ++iteri)
{
cout << *iteri << "\t";
}
cout << endl;
List<string> sList;
sList.push_back("First_YXC");
sList.push_back("Second_YXC");
sList.push_back("Third_YXC");
sList.printList();
// 通过类中类打印数据
List<string>::iterator iters;
for (iters = sList.begin(); iters != sList.end(); ++iters)
{
cout << *iters << "\t";
}
cout << endl;
List<YXC> yxcList;
yxcList.push_back(YXC("18岁的YXC",18));
yxcList.push_back(YXC("19岁的YXC", 19));
yxcList.push_back(YXC("20岁的YXC", 20));
yxcList.printList();
// 通过类中类打印数据
List<YXC>::iterator iter;
for (iter = yxcList.begin(); iter != yxcList.end(); ++iter)
{
cout << *iter;
}
// 标准库里的list
list<YXC> test;
test.push_back(YXC("18的yxc",18));
test.push_back(YXC("19的yxc",19));
test.push_back(YXC("20的yxc",20));
// 通过类中类打印数据
list<YXC>::iterator itertest;
for (itertest = test.begin(); itertest != test.end(); ++itertest)
{
cout << *itertest;
}
return 0;
}