C++模板

模板 泛型编程 类型参数化 C++高级语法

将类型参数化,实现算法与类型的分离,编写针对类型更加抽象的函数和类
sort()  可以对任意类型的数据进行排序   泛型
vector  可以存储任意类型的数据

函数模板

实现通用的函数,将函数的类型参数化

语法格式

	template<typename T>   //template<类型形式参数表>  泛型参数
	void func(T t){}
	template<类型形式参数表>   类型参数列表可以有多个类型
	template<typename T1,typename T2,...>
	template 关键字
	typename 关键字     ------   class 

函数模板中的类型参数一般用于函数的形参列表,但也可以用于函数体中定义变量

函数模板中的类型参数一般作用于形参,那么如果在调用该函数时,
可以根据实参的类型进行类型推导,从而不需要指定模板类型
	注意,有的时候根据实参也不能推导出来,必须显示提供类型参数
如果函数模板类型作用于函数体中,在调用函数时只能显示传递类型进行实例化

所谓的函数模板其实好比一个类型,需要用具体的类型来实例化成函数(模板函数)
函数模板 用具体的类型实例化 模板函数
#include <iostream>
#include <algorithm>
using namespace std;


template<typename T>
void mswap(T& t1,T& t2){
	T t = t1;
	t1 = t2;
	t2 = t;
}

template<typename T>
void msort(T elems[],size_t cnt){
	for(int i=0;i<cnt;i++){
		bool isswap = false;
		for(int j=1;j<cnt-i;j++){
			if(elems[j] < elems[j-1]){//改变这个  就能改变排序规则
				mswap(elems[j],elems[j-1]);		
				isswap = true;
			}	
		}	
		if(!isswap){
			break;	
		}
	}
}

template<typename T>
void print(T elems[],size_t cnt){
	for(int i=0;i<cnt;i++)
		cout << elems[i] << " ";
	cout << endl;
}

class Stu{
private:
	int no;
	string name;
	int s;
public:
	Stu(int no,string name,int s):no(no),name(name),s(s){}
	int getNo()const{
		return no;	
	}
	int getS()const{
		return s;	
	}
	friend ostream& operator<<(ostream& os,const Stu& s);
};

ostream& operator<<(ostream& os,const Stu& s){
	return os << s.no << " " << s.name << " " << s.s << endl;	
}
//对象  函数对象
class Comp{
public:	
	bool operator()(const Stu& s1,const Stu& s2){
		return s2.getS() < s1.getS();
	}
};

int main(){
	int arr[9] = {7,2,9,8,1,4,5,0,6};
	msort(arr,9);
	print(arr,9);
	Stu srr[5] = {Stu(110,"jack",90),Stu(120,"lily",97),
		Stu(119,"lucy",89),Stu(127,"james",99),Stu(133,"jordan",97)};
	sort(srr,srr+5,Comp());//匿名对象   匿名函数对象
	print(srr,5);
	return 0;	
}

C++为什么能够支持模板这种语法?

	C++支持重载
	函数模板根据类型实例化之后,生成了函数名相同,参数列表不同的重载函数

调用函数模板

 函数模板要先根据类型实例化 产生具体的 模板函数
        实际上调用的是 模板函数
	函数模板: 是模板    类  需要实例化对象    这个对象 称为 模板函数
	模板函数: 是函数    可以调用

函数名(实参列表);  //自动类型推导
函数名<类型参数>(实参列表);  //不能进行类型推导
#include <iostream>
using namespace std;

template<typename T>
T msum(T a,T b){
	return a+b;		
}

int main(){
	cout << msum(1,2) << endl;
	//cout << msum(1,3.1) << endl;	//不能根据实参进行类型推导
	cout << msum<double>(1,3.1) << endl; 
	cout << msum(1.0,3.1) << endl;
	return 0;	
}

特化版本的定义

函数模板有可以针对某些特殊的类型不太适用,可以为该类型编写一个特化版本的函数模板
template<>
RET_TYPE func_template_name<特化类型>(arglist...){}
#include <iostream>
#include <cstring>
using namespace std;

template<typename T>
T mmax(T a,T b){
	return a>b?a:b;	
}
//针对特殊的类型 特化的函数模板
template<>
const char* mmax<const char*>(const char* a,const char *b){
	return strcmp(a,b)>0?a:b;
} 


int main(){
	cout << mmax("ABC","abc") << endl;//调用特化版本的函数模板
	cout << mmax(3.14,5.16) << endl;
	
	return 0;	
}


函数模板有点类似于C语言中宏函数

#define MAX(a,b) ((a)>(b)?(a):(b))
int a = 1,b = 0;
MAX(++a,b);   // (++a)>(b)?(++a):(b)
但是宏容易产生意想不到的错误

类模板

类模板定义语法

template<typename T,...>
class class_template_name{};

类模板不能根据参数进行类型推导实例化模板类,只能显示
class_template_name<类型参数> 对象名(实参列表);// 这一行代码有两个实例化
	1.根据类模板加上类型参数 实例化成  模板类(具体类)
	2.根据生成的模板类 实例化 一个对象 

栈的模板

#include <iostream>
#include <stdexcept>
using namespace std;
//类模板
template<typename T=int>
class Stack{
private:
	T *elems;
	size_t size;
	size_t cap;
public:
	Stack(size_t cap = 10):cap(cap){
		elems = new T[cap];
		size = 0;
	}
	~Stack(){
		if(elems != NULL)
			delete [] elems;
		elems = NULL;
	}
	Stack(const Stack& s):elems(new T[s.cap]),size(s.size),cap(s.cap){
		for(int i=0;i<size;i++)
			elems[i] = s.elems[i];
	}
	Stack& operator=(const Stack& s){
		if(this != &s){
			Stack stmp(s);
			swap(stmp.elems,elems);//swap(stmp,*this); 调用 operator= 
			size = s.size;
			cap = s.cap;
		}	
		return *this;
	}
	bool full(){
		return size == cap;	
	}
	bool empty(){
		return size == 0;	
	}
	void push(const T& data){
		if(full()){
			throw overflow_error("栈上溢");	
		}
		elems[size++] = data;
	}
	T pop(){
		if(empty()){
			throw underflow_error("栈下溢");	
		}	
		return elems[--size];
	}
	T top(){
		if(empty()){
			throw underflow_error("栈下溢");	
		}	
		return elems[size-1];
	}
};

class Stu{};
int main(){
	Stack<> stack;
	//常引用
	int a;
	int& r = a;
	const int& rc = a;
	//int& r1 = 1;
	const int& r2 = 1;//常引用
	Stack<int> s(6);	
	Stack<double> s1;
	Stack<Stu> s2(5);
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);
	s.push(5);
	s.push(6);
	try{
		s.push(4);
	}catch(overflow_error& e){
		cout << e.what() << endl;	
	}
	
	while(!s.empty()){
		cout << s.pop() << endl;	
	}

	return 0;	
}

//队列模板(自己尝试写一下)
	template<typename T>
	class Queue{};

类模板的类型缺省

template<typename T=int>
class Comptor{}
Comptor<> c2(3,4);
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

template<typename T=int>
class Comptor{
private:
	T x;
	T y;
public:
	Comptor(const T& x,const T& y):x(x),y(y){}
	T max(){
		return x>y?x:y;	
	}
	T min(){
		return x<y?x:y;	
	}
};

//全特化
/*
template<>
class Comptor<const char*>{
private:
	const char *x;
	const char *y;
public:
	Comptor(const char* & x,const char* & y):x(x),y(y){}
	const char* max(){
		return strcmp(x,y)>0?x:y;	
	}
	const char* min(){
		return strcmp(x,y)<0?x:y;	
	}
};
*/
//成员物化
template<>
const char *Comptor<const char*>::max(){
	return strcmp(x,y)>0?x:y;	
}
template<>
const char *Comptor<const char*>::min(){
	return strcmp(x,y)<0?x:y;	
}

int main(){
	Comptor<int> c1(1,2);
	Comptor<> c2(3,4);
	cout << c2.max() << endl;
	cout << c2.min() << endl;
	const char *s1 = "hello";
	const char *s2 = "hi";
	Comptor<const char*> c3(s1,s2);
	cout << c3.max() << endl;//
	cout << c3.min() << endl;
	return 0;
}

通用的类模板

template<typename T,...>
class cla_template_name{
	
};

全特化

template<>
class cla_template_name<特化类型>{
	
};
template<>
class Comptor<const char*>{
private:
	const char *x;
	const char *y;
public:
	Comptor(const char* & x,const char* & y):x(x),y(y){}
	const char* max(){
		return strcmp(x,y)>0?x:y;	
	}
	const char* min(){
		return strcmp(x,y)<0?x:y;	
	}
};

成员特化

template<>
ret_type cla_template_name<特化类型>::memb_func_name(arglist,..){}
template<>
const char *Comptor<const char*>::max(){
	return strcmp(x,y)>0?x:y;	
}
template<>
const char *Comptor<const char*>::min(){
	return strcmp(x,y)<0?x:y;	
}

类模板在实例化时一定要显示类型实例化
类模板可以有缺省类型,类模板也可以有普通模板参数(非类型模板参数)

类模板的非类型参数 及 模板缺省值

1.非类型参数的实参仅限于常量或者常量表达式
	//int a = 10;
	//Array<int,a> arr4;//这里a不是常量,所以这样是错的
	const int ci = 10;
	Array<int,ci> arr5;//c++中const定义的是常量,这样定义正确
2.无论是类型参数还是非类型参数,都可以带缺省值,但是和函数的缺省值一样
	要满足靠右原则
#include <iostream>
using namespace std;

//类模板的缺省参数 靠右原则
template<typename T=int,int LEN=5>
class Array{
private:
	T arr[LEN];
public:
	const T& operator[](int index)const{
		return arr[index];
	}
	T& operator[](int index){
		return arr[index];	
	}
};

int main(){
	//Array arr;  <>括号必须得写
	Array<> arr1;
	arr1[0] = 1;
	arr1[1] = 100;
	Array<double> arr2;
	Array<string,4> arr3;
	arr3[0] = string("Hello");
	int a = 10;
	//Array<int,a> arr4;
	const int ci = 10;
	Array<int,ci> arr5;
	return 0;	
}

局部特化(类中的成员函数是模板) 偏特化

1.普通的类  某些成员函数是模板
#include <iostream>
#include <typeinfo>
using namespace std;
//普通的类  不是类模板
class A{
	
public:
	//成员函数模板 
	template<typename T>
	void func(T t){
		cout << typeid(T).name() << endl;	
	}
	template<typename T>
	void func(){
		T t;
		cout << typeid(T).name() << endl;
	}
	void show(){
		cout << typeid(*this).name() << endl;	
	}
};


int main(){
	A a;
	a.show();
	a.func(1);
	a.func(3.14);
	a.func(a);
	a.func(3.14);
	a.func<float>(3.14);
	a.func<int>();
	a.func<A>();
	a.func<double>();
	return 0;
}

2.针对指针和数组进行偏特化
3.针对模板类型偏特化
#include <iostream>
using namespace std;

//针对类型局部特化
template<typename T,typename N>
class A{
public:
	A(){
		cout << "A<T,N>" << endl;	
	}
};
//偏特化
template<typename T>
class A<T,int>{
public:
	A(){
		cout << "A<T,int>" << endl;	
	}
};
template<>
class A<int,int>{
public:
	A(){
		cout << "A<int,int>" << endl;	
	}
};

template<typename T>
class B{
public:
	B(){
		cout << "B<T>" << endl;	
	}
};
//针对指针实现偏特化
template<typename T>
class B<T*>{
public:
	B(){
		cout << "B<T*>" << endl;	
	}
};
//针对数组实现偏特化
template<typename T>
class B<T[]>{
public:
	B(){
		cout << "B<T[]>" << endl;	
	}
};

template<typename T1,typename T2,typename T3>
class C{
public:
	C(void){
		cout << "C<T1,T2,T3>" << endl;	
	}
};

template<typename T1,typename T2>
class C<T1,T2,T2>{
public:
	C(void){
		cout << "C<T1,T2,T2>" << endl;	
	}
};


template<typename T>
class C<T,T,T>{
public:
	C(void){
		cout << "C<T,T,T>" << endl;	
	}
};

template<typename T>
class C<T,T*,T*>{
public:
	C(void){
		cout << "C<T,T*,T*>" << endl;	
	}
};

int main(){
	//选择特化程序更高的版本
	A<int,int> a;  //全特化  A<int,int>
	A<double,int> b; //偏特化  A<T,int>
	A<short,double> c; //通用    A<T,N>
	//针对指针和数组进行偏特化  如果类型为指针和数组会选择指针和数组偏特化的版本
	B<int*> d;
	B<int[]> e;
	B<int> f;
	//匹配度高的特化优先
	C<int,int,int> g;
	C<int,int*,int*> h;

	return 0;	
}

模板继承、模板成员问题:

1.从类模板继承 普通类 类模板

#include <iostream>
using namespace std;

//类模板
template<typename T>
class A{
private:
	T t;
public:
	A(const T& t):t(t){
		cout << "A构造" << endl;	
	}
	T& get(){
		return t;	
	}
	const T& get()const{
		return t;	
	}
};

//普通类
class B:public A<int>{
private:
	int m;
public:
	B(int a,int b):A(a),m(b){
		cout << "B构造" << endl;		
	}
	void show()const{
		cout << get() << ":" << m << endl;	
	}
};

//类模板继承类模板
template<typename T,typename N>
class C:public A<T>{
private:
	N n;
public:
	C(const T& t,const N& n):A<T>(t),n(n){//调用基类类模板的构造函数需要类型参数
		cout << "C构造" << endl;
	}
	void show(){
		cout << A<T>::get() << ":" << n << endl;//调用基类类模板的普通函数类型参数
	}
};



int main(){
	B b(1,200);
	b.show();
	cout << b.get() << endl;
	C<int,int> c(3,4);
	c.show();
	return 0;	
}

以前写的Shape Rect Circle实例

#include <iostream>
using namespace std;

template<typename BASE>
class Shape:public BASE{
public:
	void draw(void)const{
		BASE::draw();	
	};
};


class Rect{
public:
	void draw(void)const{
		cout << "draw rect..." << endl;	
	}
};

class Circle{
public:
	void draw(void)const{
		cout << "draw circle..." << endl;	
	}
};

int main(){
	//Shape<int> s;//Shape:public int  错误的
	Shape<Rect> s1;
	Shape<Circle> s2;
	s1.draw();
	s2.draw();
	return 0;	
}

2.向类模板派生

#include <iostream>
using namespace std;

template<typename BASE>
class Shape:public BASE{
public:
	void draw(void)const{
		BASE::draw();	
	};
};


class Rect{
public:
	void draw(void)const{
		cout << "draw rect..." << endl;	
	}
};

class Circle{
public:
	void draw(void)const{
		cout << "draw circle..." << endl;	
	}
};

int main(){
	//Shape<int> s;//Shape:public int  错误的
	Shape<Rect> s1;
	Shape<Circle> s2;
	s1.draw();
	s2.draw();
	return 0;	
}

3.类模板中的模板成员

a.模板型成员变量

#include <iostream>
using namespace std;

template<typename T>
class A{
private:
	T t;
public:
	A(const T& t):t(t){
		cout << "A" << endl;	
	}
	T& get(){
		return t;	
	}
};
//类模板
template<typename T,typename N>
class B{
private:
	A<T> a;//类模板作为类的成员变量
	N b;
public:
	B(const T& t,const N& b):a(t),b(b){
		cout << "B" << endl;	
	}
	void show(){
		cout << a.get() << ":" << b << endl;	
	}
};

class C{
private:
	A<string> a;
public:
	C(const string& s):a(s){
		cout << "C" << endl;	
	}
	void show(){
		cout << a.get() << endl;	
	}
};
int main(){
	B<string,int> o("hello c++",1024);
	o.show();
	
	C c("hello java");
	c.show();

	return 0;
}

b.模板型成员函数

#include <iostream>
using namespace std;

template <typename T>
class A{
private:
	T t;
public:
	A(const T& t):t(t){
		cout << "A" << endl;	
	}
	/*
	template<typename N>
	void show(const N& n){
		cout << t << ":" << n << endl;
	}
	template<typename N>
	void bar(){
		N n;
		cout << "bar" << endl;
	}
	*/
	template<typename N>
	void show(const N& n);
	template<typename N>
	void bar();
};

template<typename T>
	template<typename N>
void A<T>::show(const N& n){
	cout << t << ":" << n << endl;	
}

template<typename T>
	template<typename N>
void A<T>::bar(){
	N n;
	cout << "bar" << endl;
}

int main(){
	A<string> a("Hello");
	a.show<int>(100);
	a.bar<int>();
	return 0;	
}

c.模板型成员类型

#include <iostream>
using namespace std;


template<typename T,typename M>
class A{
public:
	//模板型成员类型
	/*
	template<typename N>
	class B{
	public:
		B(const N& n):n(n){
			
		}
		N n;
	};
	*/
	template<typename N> class B;//声明
	A(const T& t,const M& m):t(t),m(m){
		
	}
	void show(){
		cout << t << ":" << m.n << endl;	
	}
private:
	T t;
	B<M> m;//M --> N
};

template<typename T,typename M>
	template<typename N>
class A<T,M>::B{
public:
	N n;
	B(const N& n):n(n){
		
	}
};


int main(){
	A<string,int> a("hello",1024);
	a.show();
	return 0;	
}

4.模板型模板实参

	template<typename X,typename Y,template<typename T> class Z>
	Z必须是一个类模板  而不是具体的类型
#include <iostream>
#include <vector>
using namespace std;

template<typename T>
class A{
private:
	T t;
public:
	A(const T& t):t(t){
		
	}
	T get(){
		return t;	
	}
};

template<typename X,typename Z,template<typename T> class Y>  //类模板的第三个类型参数一定是类模板
class B{
public:
	Y<X> x; 
	Y<Z> z;
	B(const X& x,const Z& z):x(x),z(z){
		
	}
};

int main(){
	B<string,int,A> b("Hello",1024);
	cout << b.x.get() << endl; //A<string>
	cout << b.z.get() << endl; //A<int>
	//vector<vector<int>> v;  C++11之前 >> 一定要有空格
	vector<vector<int> > v;
	return 0;	
}

STL 用模板的语法实现一些通用容器和算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值