【第12节 C++模板】

函数模板

什么是模板: 把类型当做未知量,可以忽略类型影响

#include<iostream>
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;
}
//引入模板这个东西
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty

_Ty Max(_Ty a, _Ty b)
{
	return a > b ? a : b;
}

int main()
{
	return 0;
}

声明模板的语法

//单个未知类型
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty    _Ty 随便改 ,就是类型代号
Ty Max(_Ty a, _Ty b)
{
	return a > b ? a : b;
}
//可以多个未知类型
template <typename _Ty1,typename _Ty2>
void print(_Ty1 one ,_Ty2 two)
{
    cout<<one<<endl;
    cout<<two<<endl;
}
//typename 可以换成class
template <class T>
void print(T a)
{
    cout<<a<<endl;
}

调用函数模板

  • ​ 隐式调用 : 正常的函数传参即可调用

    #include<iostream>
    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;
    }
    //引入模板这个东西
    template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty    _Ty 随便改 ,就是类型代号
    _Ty Max(_Ty a, _Ty b)
    {
    	return a > b ? a : b;
    }
    
    int main()
    {  
    	//隐式调用
    	cout << Max(1, 2) << endl;
    	cout << Max("string", "string")<<endl;
    	cout << Max(1.1, 2.3 << endl;
    	return 0;
    }
    
  • ​ 显示调用: 函数名<类型名>(参数)

    #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;
    }
    //引入模板这个东西
    template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty    _Ty 随便改 ,就是类型代号
    _Ty Max(_Ty a, _Ty b)
    {
    	return a > b ? a : b;
    }
    //_Ty =string a="abc" b="abc"
    
    template <class _Ty1, class _Ty2> 
    void print(_Ty1 one ,_Ty2 two)
    {
    	cout << one << endl;
    	cout << two << endl;
    }
    int main()
    {  
    	//隐式调用
    	cout << Max(1, 2) << endl;
    	cout << Max("string", "string")<<endl;
    	cout << Max(1.1, 2.3) << endl;
    
    	//显示调用
    	cout << Max<string>("abc", "abd") << endl;
    	print<string, string>("string1", "string2");
    	print<string, int>("string1", 123);
    	return 0;
    }
    

函数模板的两种形态

  • ​ 普通函数当做函数模板

  • ​ 类的成员函数是函数模板

    #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;
    }
    //引入模板这个东西
    template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty    _Ty 随便改 ,就是类型代号
    _Ty Max(_Ty a, _Ty b)
    {
    	return a > b ? a : b;
    }
    //_Ty =string a="abc" b="abc"
    
    template <class _Ty1, class _Ty2> 
    void print(_Ty1 one ,_Ty2 two)
    {
    	cout << one << endl;
    	cout << two << endl;
    }
    class MM
    {
    public:
    	template <class _Ty>
    	void print(_Ty data)
    	{
    		cout << data << endl;
    	}
    	template <class _Ty>
    	void printData(_Ty data);
    protected:
    	string name;
    	int age;
    };
    //在类外实现的时候不能省略template这一块
    template <class _Ty>
    void MM::printData(_Ty data)
    {
    	cout << data << endl;
    }
    int main()
    {  
    	//隐式调用
    	cout << Max(1, 2) << endl;
    	cout << Max("string", "string")<<endl;
    	cout << Max(1.1, 2.3) << endl;
    
    	//显示调用
    	cout << Max<string>("abc", "abd") << endl;
    	print<string, string>("string1", "string2");
    	print<string, int>("string1", 123);
    
    	//类照曝光额成员函数是函数模板
    	MM mm;
    	mm.print(123);
    	mm.print<string>("ILoveyou");
    	mm.printData(12345);
    	return 0;
    }
    

函数模板特殊的写法

  • ​ 缺省写法

    #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;
    }
    //引入模板这个东西
    template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty    _Ty 随便改 ,就是类型代号
    _Ty Max(_Ty a, _Ty b)
    {
    	return a > b ? a : b;
    }
    //_Ty =string a="abc" b="abc"
    
    template <class _Ty1, class _Ty2> 
    void print(_Ty1 one ,_Ty2 two)
    {
    	cout << one << endl;
    	cout << two << endl;
    }
    class MM
    {
    public:
    	template <class _Ty>
    	void print(_Ty data)
    	{
    		cout << data << endl;
    	}
    	template <class _Ty>
    	void printData(_Ty data);
    protected:
    	string name;
    	int age;
    };
    //在类外实现的时候不能省略template这一块
    template <class _Ty1>
    void MM::printData(_Ty data)
    {
    	cout << data << endl;
    }
    
    template <class _Ty1, class _Ty2 = int>
    void printData(_Ty1 one, _Ty2 two)
    {
    	cout << one << "\t" << two << endl;
    }
    
    void testFunc()
    {
    	printData("string", 1234);
    	//函数模板的缺省,显示调用,可以不用传类型,但是参数是不能少的
    	printData<string>("ILoveyou", 1234);
    }
    int main()
    {  
    	//隐式调用
    	cout << Max(1, 2) << endl;
    	cout << Max("string", "string")<<endl;
    	cout << Max(1.1, 2.3) << endl;
    
    	//显示调用
    	cout << Max<string>("abc", "abd") << endl;
    	print<string, string>("string1", "string2");
    	print<string, int>("string1", 123);
    
    	//类照曝光额成员函数是函数模板
    	MM mm;
    	mm.print(123);
    	mm.print<string>("ILoveyou");
    	mm.printData(12345);
    
    	//模板函数可不可缺省
    	return 0;
    }
    
  • ​ 存在常量类型

    #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;
    }
    //引入模板这个东西
    template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty    _Ty 随便改 ,就是类型代号
    _Ty Max(_Ty a, _Ty b)
    {
    	return a > b ? a : b;
    }
    //_Ty =string a="abc" b="abc"
    
    template <class _Ty1, class _Ty2> 
    void print(_Ty1 one ,_Ty2 two)
    {
    	cout << one << endl;
    	cout << two << endl;
    }
    class MM
    {
    public:
    	template <class _Ty>
    	void print(_Ty data)
    	{
    		cout << data << endl;
    	}
    	template <class _Ty>
    	void printData(_Ty data);
    protected:
    	string name;
    	int age;
    };
    //在类外实现的时候不能省略template这一块
    template <class _Ty1>
    void MM::printData(_Ty data)
    {
    	cout << data << endl;
    }
    
    template <class _Ty1, class _Ty2 = int>
    void printData(_Ty1 one, _Ty2 two)
    {
    	cout << one << "\t" << two << endl;
    }
    //存在传常量写法
    //size_t:unsigned int 的别名
    template <class _Ty1,size_t size=3>
    void printArray(_Ty1 array)//_Ty1 = int* size=3
    {
    	for (int i = 0; i < size; i++)
    	{
    		cout << array[i];
    	}
    	cout << endl;
    }
    
    void testFunc()
    {
    	printData("string", 1234);
    	//函数模板的缺省,显示调用,可以不用传类型,但是参数是不能少的
    	printData<string>("ILoveyou", 1234);
    	int array[3] = { 1, 2, 3 };
    	//没有做缺省必须显示调用
    	printArray<int*,3>(array);
    	//做了缺省可以隐式调用
    	printArray(array);
    
    	//不能传入变量,只能传入常量,函数模板如果存在变量的情况下
    	/*int size = 3;
    	printArray<int*, size>(array);*/
    }
    int main()
    {  
    	//隐式调用
    	cout << Max(1, 2) << endl;
    	cout << Max("string", "string")<<endl;
    	cout << Max(1.1, 2.3) << endl;
    
    	//显示调用
    	cout << Max<string>("abc", "abd") << endl;
    	print<string, string>("string1", "string2");
    	print<string, int>("string1", 123);
    
    	//类照曝光额成员函数是函数模板
    	MM mm;
    	mm.print(123);
    	mm.print<string>("ILoveyou");
    	mm.printData(12345);
    
    	//模板函数可不可缺省
    	return 0;
    }
    

类模板

如何生成一个类模板

template<class _Ty>
class MM
{
   public:
   protected:
}
//只要被template修饰就是一个模板类,用没用未知类型没有关系

类模板调用

  • 必须采用显式调用

    #include <iostream>
    using namespace std;
    //template <>
    //class Data
    //{
    //
    //};
    template <class _Ty>
    class MM
    {
    public:
    protected:
    };
    
    int main()
    {
    	//必须采用显示调用
    	MM<int> mm;
    	MM<string> mm2;
    	MM<double> mm3;
    	//MM mm;错误的!
    	return 0;
    }
    
  • 类模板不是一个实际类型,所以所有用到类名的地方都需要使用: 类名<未知类型> 方式使用

    #include <iostream>
    using namespace std;
    //template <>
    //class Data
    //{
    //
    //};
    
    template <class _Ty>
    class MM
    {
    public:
    	MM(){};
    	MM(string name):name(name){}
    	void print();
    protected:
    	string name;
    };
    //在类外实现
    template <class _Ty>
    void MM<_Ty>::print()
    {
    	cout << "类模板" << endl;
    }
    
    template <class _Ty>
    class Girl :public MM<_Ty>
    {
    public:
    	Girl(string name) :MM<_Ty>(name)
    	{
    
    	}
    protected:
    };
    int main()
    {
    	//必须采用显示调用
    	MM<int> mm;
    	MM<string> mm2;
    	MM<double> mm3;
    	//MM mm;错误的!
    	Girl<int> girl("Loveyou");
    	girl.print();
    
    	return 0;
    }
    
  • 多文件中,类模板 中的声明和实现一定在一起的,不能分开写。

    #include <iostream>
    using namespace std;
    //template <>
    //class Data
    //{
    //
    //};
    
    template <class _Ty>
    class MM
    {
    public:
    	MM(){};
    	MM(string name):name(name){}
    	void print();
    protected:
    	string name;
    };
    //在类外实现
    template <class _Ty>
    void MM<_Ty>::print()
    {
    	cout << "类模板" << endl;
    }
    
    template <class _Ty>
    class Girl :public MM<_Ty>
    {
    public:
    	Girl(string name) :MM<_Ty>(name)
    	{
    
    	}
    protected:
    };
    template <class _Ty1,class _Ty2>
    class Data
    {
    public:
    	Data(_Ty1 one, _Ty2 two) :one(one), two(two){}
    	void print();
    protected:
    	_Ty1 one;
    	_Ty2 two;
    };
    
    template <class _Ty1, class _Ty2>
    void Data<_Ty1, _Ty2>::print()
    {
    	cout << one << endl;
    	cout << two << endl;
    }
    
    int main()
    {
    	//必须采用显示调用
    	MM<int> mm;
    	MM<string> mm2;
    	MM<double> mm3;
    	//MM mm;错误的!
    	Girl<int> girl("Loveyou");
    	girl.print();
    
    	Data<string, int> mmInfo("小芳",19);
    	mmInfo.print();
    	Data<int, int> data(12, 10);
    	data.print();
    	return 0;
    }
    

自定义类型当做模板参数

基本自定义类型

自定义类型也是一个模板

模板传入自定义类型,关键点就在于重载运算符

#include<iostream>
#include<string>
using namespace std;

class MM
{
public:
	MM(string name, int age) :name(name), age(age){}
	friend ostream& operator<<(ostream& out, MM& mm)
	{
		out << mm.name << " " << mm.age;
		return out;
	}
	bool operator>(MM& mm) const
	{
		return this->age > mm.age;
	}
protected:
	string name;
	int age;
};


template <class _Ty>
void print(_Ty one)
{
	//错误	1	error C2679: 二进制“<<”: 没有找到接受“std::string”类型的右操作数的运算符(或没有可接受的转换)	c:\users\administrator\desktop\mycjiajiapro\consoleapplication11\consoleapplication11\源.cpp	17	1	ConsoleApplication11

	cout << one << endl;
}


template <class _Ty>
_Ty Max(_Ty a, _Ty b)
{
	//错误	5	error C2784: “bool std::operator >(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)”: 未能从“MM”为“const std::reverse_iterator<_RanIt> &”推导 模板 参数	c:\users\administrator\desktop\mycjiajiapro\consoleapplication11\consoleapplication11\源.cpp	37	1	ConsoleApplication11

	return a > b ? a : b;
}

int main()
{
	//函数模板传入自定义类型
	print(12);
	print<string>("string");
	print(MM("mm", 19));

	MM xiaoF("小芳", 18);
	MM xiaoL("小丽", 28);

	MM result = Max<MM>(xiaoF, xiaoL);
	//MM result = Max(xiaoF, xiaoL);函数模板可以隐式调用
	cout << result << endl;
	return 0;
}
#include <iostream>
using namespace std;

class MM
{
public:
	MM(string name, int age) :name(name), age(age) {}
	friend ostream& operator<<(ostream& out, const MM& mm)
	{
		out << mm.name << " " << mm.age;
		return out;
	}
	bool operator>(MM& mm) const 
	{
		return this->age > mm.age;
	}
protected:
	string name;
	int age;
};
template <class _Ty>
void print(_Ty one) 
{
	//error C2679: 二进制“<<”: 没有找到接受“_Ty”类型的右操作数的运算符(或没有可接受的转换)
	cout << one << endl;
}
template <class _Ty>
_Ty Max(_Ty a, _Ty b) 
{
	//rror C2676: 二进制“>”:“_Ty”不定义该运算符或到预定义运算符可接收的类型的转换
	return a > b ? a : b;
}

template <class _Ty>
class Node
{
public:
	Node(_Ty data, Node<_Ty>* next) :data(data), next(next) {}
	_Ty getData() 
	{
		return data;
	}
	Node<_Ty>* getNext()
	{
		return next;
	}
protected:
	_Ty data;
	Node<_Ty>* next;
	//正常写法:Node* next;
};
template <class _Ty>
class List 
{
public:
	List() 
	{
		headNode = nullptr;
	}
	void insertList(_Ty data) 
	{
		headNode = new Node<_Ty>(data, headNode);
	}
	void printList()
	{
		Node<_Ty>* pmove = headNode;
		while (pmove != nullptr) 
		{
			//error C2679: 二进制“<<”: 没有找到接受“_Ty”类型的右操作数的运算符(或没有可接受的转换)
			cout << pmove->getData() << endl;
			pmove = pmove->getNext();
		}
		cout << endl;
	}
protected:
	Node<_Ty>* headNode;
};
void testList() 
{
	List<int> list;
	list.insertList(1);
	list.insertList(2);
	list.insertList(3);
	list.printList();
	List<MM> mmList;
	mmList.insertList(MM("小芳", 18));
	mmList.insertList(MM("小丽", 28));
	mmList.insertList(MM("小美", 38));
	mmList.printList();
}

int main() 
{
	//函数模板传入自定义类型
	print(12);
	print<string>("string");
	print(MM("mm", 19));

	MM xiaoF("小芳", 18);
	MM xiaoL("小丽", 28);
	MM result = Max<MM>(xiaoF, xiaoL);
	//MM result = Max(xiaoF, xiaoL);  函数模板可以隐式调用
	cout << result << endl;
	testList();


	return 0;
}

模板嵌套

明白类型是什么即可,适当可以借用using语法起别名 简化代码

#include <iostream>
using namespace std;
template <class _Ty1, class _Ty2>
class MM
{
public:
	MM(_Ty1 one, _Ty2 two) :one(one), two(two) {}
	friend ostream& operator<<(ostream& out, const MM& mm)
	{
		out << mm.one << " " << mm.two;
		return out;
	}
protected:
	_Ty1 one;
	_Ty2 two;
};

template <class _Ty1, class _Ty2>
class Data
{
public:
	Data(_Ty1 one, _Ty2 two) :one(one), two(two) {}
	void print()
	{
		cout << one << " " << two << endl;
	}
protected:
	_Ty1 one;
	_Ty2 two;
};
void testFunc()
{
	//_Ty1类型是:MM<string,int>
	//_Ty2类型是:MM<double,double>
	Data<MM<string, int>, MM<double, double>>
		data(MM<string, int>("小芳", 18), MM<double, double>(89, 56));
	data.print();
	//上面两行 等效下面四行代码
	MM<string, int> mmData("小芳", 18);
	MM<double, double> mmScore(89, 56);
	Data<MM<string, int>, MM<double, double>> mData(mmData, mmScore);
	mData.print();
}


template <class _Ty>
void print(_Ty data)
{
	cout << data << endl;
}
int main()
{
	//隐式调用
	print(MM<string, int>("小芳", 32));
	//显示调用
	//类型:MM<string, int>
	print<MM<string, int>>(MM<string, int>("小美", 238));
	//起别名简化代码
	using MMType = MM<string, int>;
	print<MMType>(MMType("小美", 238));

	testFunc();
	return 0;
}

函数模板重载

模板和普通函数 ,调用函数函数类型一致情况 优先调用普通函数

两个模板同时成立,优先调用类型相似度高的那个

类模板特化

局部特化

完全特化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值