Cpp模板入门

模板

使用模板的程序设计,就是泛型程序设计

函数模板

void Swap(int& x,int& y)
{
    int tmp=x;
    x=y;
    y=tmp;
}
void Swap(double& x,double& y)
{
    double tmp=x;
    x=y;
    y=tmp;
}
//这两个函数时重载关系
//能否只写一个Swap就能交换各种类型的变量

形式

template<class 类型参数1class 类型参数2,……>
返回值类型 模板名(形参表)
{
    函数体
};
eg:
template<class T>
    //T就是类型参数
void Swap(T& x,T &y)
{
    T tmp=x;
    x=y;
    y=tmp;
}
#include<iostream>
using namespace std;
template<class T>
void Swap(T &a,T &b)
{
    T tmp=a;
    a=b;
    b=tmp;
}
int main()
{
    int n=1,m=2;
    cout<<n<<" "<<m<<endl;
    Swap(n,m);
    //编译器自动生成具体类型
    //eg 生成void Swap(int &a,int &b);
    cout<<n<<" "<<m<<endl;
    double x=1.9,y=8.1;
    cout<<x<<" "<<y<<endl;
    Swap(x,y);
    cout<<x<<" "<<y<<endl;
}
//!!!函数模板中可以有不止一个类型参数
template<class T1,class T2>
T2 Print(T1 arg1,T2 arg2)
{
    ……
}
//求数组最大元素的MaxElement函数模板
#include<iostream>
using namespace std;
template<class T>
T MaxElement(T* a,int size)
{
    T tmpMax=a[0];
    for(int i=1;i<size;i++)
    {
        if(tmpMax<a[i])
        {
            tmpMax=a[i]
        }
    }
    return tmpMax;
}
//就可以满足各种数据类型的数组传进来

将模板数据类型补充,称为模板的实例化

编译器走到这一步就实例化完全

不通过参数实例化函数模板

#include<iostream>
using namespace std;
template<class T>
T Inc(T n)
{
    return n+1;
}
int main()
{
    cout<<Inc<double>(4)/2<<endl;//=>2.5
    //即使你传进去的是int 4,但是输出依然是浮点数
    //首先尊重double的声明
    //不通过参数实例化,就是我已经很确定这一句运行时,应该是什么数据类型
    //<表明类型>(形参表传入参数)
}

函数模板和函数的次序

  • 在有多个函数和函数模板名字相同的情况下,编译器处理
    • 先找函数完全匹配的普通函数(未模板实例化的)
    • 再找参数完全匹配的模板函数
    • 再找实参经过自动类型转换之后能匹配的函数
    • 否则,error
template<class T,class T2>
void Max(T a,T2 b)
{
	cout<<"Yes"<<endl;
}
int main()
{
	Max(5,6);
}
//匹配模板函数时,编译器不会帮你自动类型转换
//如果T a,T b
//但是,a是int,b是double就报错,T不能转变成既是int又是double的数
//T a,T2 a
//两个都是int是可以的

典型模板——Map

#include <iostream>
using namespace std;
//Map的作用是,将区间s到e这一段,通过函数指针op的处理后,拷贝到x
template<class T,class Pred>
void Map(T s,T e,T x,Pred op)//通常实例化的时候,s和e都是指针,x是指针,op是函数指针
{
	for(;s!=e;++s,++x)
	{
		*x=op(*s);
	}	
}
int Cube(int x)
{
	return x*x*x;
}
double Square(double x)
{
	return x*x;
}

int a[5]={1,2,3,4,5},b[5];//a是原区间,b是目标区间
double d[5]={1.1,2.1,3.1,4.1,5.1},c[5];
int main()
{
	//希望你能回忆起函数指针
    //(*op)(double)//函数指针(函数形参表)
	Map(a,a+5,b,Square);
	for(int i=0;i<5;i++)
		cout<<b[i]<<" ";
	cout<<endl;

	Map(a,a+5,b,Cube);
	for(int i=0;i<5;i++)
		cout<<b[i]<<" ";
	cout<<endl;

	Map(d,d+5,c,Square);
	for(int i=0;i<5;i++)
		cout<<c[i]<<" ";
	cout<<endl;
}

类模板

为了快速生成相似的类,定义类模板,然后由类模板生成不同的类

例如写一个数组的类,数组里面存储类型不同,你放的东西也不同

因此可以用模板类解决

//成员变量 类似但数据类型不相同

//形式
template<class T,class T1>
//template<typename T,typename T1>//也可以
class 类模板名
{
    成员函数和成员变量
};


//类模板里成员函数的写法
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{
    ......
}

//用类模板定义对象的写法:
类模板名<真实类型参数表> 对象名(构造函数实参表)

类模板——Pair类模板

#include <iostream>
using namespace std;
template<typename T1,typename T2>
class Pair
{
	public:
		T1 key;	//关键字
		T2 value;//值
		Pair(T1 k,T2 v):key(k),value(v){ };
		//这个重载< 用于自定义排序规则,传入参数是同类的另一个对象
		//因为这个是类模板,所以应该得是类型也一样的同类
		bool operator<(const Pair<T1,T2> &p)const;
};

template<class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2>& p)const
{
	return key<p.key;
	//按key的大小 从小到大排序
}

int main()
{
	Pair<string,int> student("name",100);
    //实例化出对象,要现有对应的真实数据类型
	cout<<student.key<<" "<<student.value<<endl;
}

同一个类模板的两个模板类是不兼容的

函数模板作为类模板成员

成员函数是一个函数模板

#include <iostream>
using namespace std;
template<typename T>
class A
{
	public:
		template<class T2>
		void Func(T2 t)
		{
			cout<<t<<endl;
		}
};
int main()
{
	A<int> a;
	a.Func(33);//成员函数模板化
	a.Func("Hello");
}

类模板与派生

  • 类模板 从 类模板派生
  • 类模板 从 模板类派生
  • 类模板 从 普通类派生
  • 普通类 从 模板类派生
//类模板 从 类模板派生
template<typename T1,typename T2>
class A
{
	T1 v1;
	T2 v2;
};

template<typename T1,typename T2>
//派生下来的同时,要把基类进行实例化
//B<int,double> obj1;
//=> class B<int,double>:public A<double,int>{}
class B:public A<T2,T1>
{
	T1 v3;
	T2 v4;
};

template<class T>
class C:public B<T,T>
{
	T v5;
};
//类模板 从模板类派生
template<typename T1,typename T2>
class A
{
	T1 v1;
	T2 v2;
};

template<class T>
class C:public A<int,double>
{
	T v5;
};

int main()
{
	C<char> obj1;
	//就会生成基类A<int,double>
}
//从普通类继承,就和已被实例化的类模板一样
//普通类从模板类继承,需要保证模板类已被实例化

类模板和友元

//函数、类和类的成员函数作为类模板的友元
//则由这个模板生成的所有类,都有这些友元
template<typename T1,typename T2>
class A
{
	T1 v1;
	T2 v2;
	public:
		friend void Func1();
		friend class B;
		friend void B::Func();
};


//函数模板作为类模板的友元
template<typename T1,typename T2>
class Pair
{
	public:
		T1 key;	//关键字
		T2 value;//值
		Pair(T1 k,T2 v):key(k),value(v){ };
		bool operator<(const Pair<T1,T2> &p)const;
		template<class T3,class T4>
		friend ostream& operator<<(ostream& o,const Pair<T3,T4>& p);
};
//则由这个Pair模板生成的所有类,都有这个重载左移运算符的函数模板



//类模板做类模板的友元
//那么这个友元模板在使用类时,要先将其实例化
template<class T>
class B
{
    private:
    	int v;
    public:
    	template<class T2>
    	friend class A;
};
template<class T2>
class A
{
    B<int> o(10);//先实例化
    void Func()
    {
        cout<<o.v<<endl;
    }
}

类模板与static成员

类模板钟同样可以定义静态成员,那么从该类模板实例化得到的所有类包含同样的静态成员

实例化不同的类,静态成员变量不同,要实例化相同的类才共用一个静态成员变量

//静态成员变量的声明:
template<> int A<int>::count=0;
template<> int A<double>::count=0;

三维数组——内部类

template <class T>
class CArray3D
{
	private:
		T *array;
		int i,j,k;
	public:
		CArray3D(int _i,int _j,int _k):i(_i),j(_j),k(_k)
		{
			array=new T[_i*_j*_k];
		}
		~CArray3D()
		{
			delete[] array;
		}

		class CArray2D
		{
			private:
				T *arrayTwo;
				int k2;
			public:
				CArray2D(T *_arrayTwo,int _k2):arrayTwo(_arrayTwo),k2(_k2){ }
				T* operator[](int j2)
				{
					return arrayTwo+j2*k2;
				}
				operator T*()
				{
					return arrayTwo;
				}
		};

		CArray2D operator[](int x)
		{
			T* arrayTwo=array+x*j*k;
			return CArray2D(arrayTwo,k);
		}
};
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Caaaaaan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值