C++模板/泛型编程

本文深入介绍了C++中的模板编程,包括函数模板和类模板的使用。通过实例展示了如何创建和使用模板,如Max函数模板、自定义类型与模板的结合、模板类的静态成员、模板类的特化等。此外,还讨论了模板类的嵌套以及封装模板链表的实现。内容涵盖了模板的基本概念、模板类的声明和实例化,以及模板在实际编程中的应用。
摘要由CSDN通过智能技术生成

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;
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值