首先让我们来看一段代码的实现
#include <iostream>
using namespace std;
int add(int x,int y)
{
return x+y;
}
double add(double x,double y)
{
return x+y;
}
int add(char x,char y)
{
return x+y;
}
int main()
{
cout<<add(1,2)<<endl;
cout<<add(3.1,2.3)<<endl;
cout<<add('a','2')<<endl;
return 0;
}
tips: int 和 char 可以隐式转换
我们如何只写一个函数就能实现下面三种不能类型数据的相加呢?
这里就要用到模板的知识,那我们来看模板。
一.模板
c++模板:是支持参数多态化的工具。
实质:设计一种通用类型的函数或类,在函数或类使用时,让数据成员,成员函数,函数返回值在实际使用时可以是任意类型。
目的:让程序员编写与类型无关的代码,是范型编程的基础。
函数模板:
? ? ? ? 针对函数参数类型不同的函数。
类模板:
? ? ? ? 针对数据成员,成员函数数据类型,参数类型不同的类
1.函数模板语法结构:
?templata <类型模板形参列表>类型模板形参 函数名(<形参列表>)
注意:
? ? ? ? ? ? ? ?templata:模板说明的关键字
? ? ? ? ? ? ? ? <类型模板形参列表>:用class或typename定义的变量,多个模板形参之间以空格隔开
? ? ? ? ? ? ? ? 1.class T1:定义类型模板形参 T1,用来代替函数的相关数据类型。
? ? ? ? ? ? ? ? eg:
? ? ? ? ? ? ? ? ? ? ? ? template<class T1>T1 add(T1 X,T1 Y);
把开头的例子用模板实现:
? ? ? ?
#include <iostream>
using namespace std;
template<typename T1>T1 add(T1 ,T1);//函数模板声明
template<class T1> //函数模板声明
T1 add(T1 x,T1 y) //函数模板定义
{
return x+y;
}
int main()
{
cout<<add(1,2)<<endl;
cout<<add(3.1,2.3)<<endl; //函数模板的 隐式调用,自动匹配数据类型
cout<<add('a','2')<<endl;
return 0;
}
typename与class 原来C++只有class,但是对于初学者理解容易与类定义混淆 为了方便理解,后面的版本是加入了typename关键字方便教学使用,学校C++教材上有提过 有隐式调用就有显示调用
下面就是显示调用
#include <iostream>
using namespace std;
template<typename T1>T1 add(T1 ,T1);//函数模板声明
template<class T1> //函数模板声明
T1 add(T1 x,T1 y) //函数模板定义
{
return x+y;
}
int main()
{
cout<<add(1,2)<<endl;
cout<<add(3.1,2.3)<<endl; //函数模板的 隐式调用,自动匹配数据类型
cout<<add('a','2')<<endl;
cout<<add<>(2,5)<<endl; //函数模板的显示调用
cout<<add<int>(5,6)<<endl; //显示调用,指定模板性参 为int,是将int传递给了T1
cout<<add<float>(3.12 ,4.1)<<endl;
return 0;
}
如果是两个不同类型的数相加可以实现吗?
答案也是可以的。
例子:
#include <iostream>
using namespace std;
template<class T1,class T2>
T1 add(T1 x,T2 y)
{
return x+y;
}
int main()
{
cout<<add(2.1,2)<<endl;
cout<<add<>(2,2.1 )<<endl;
cout<<add<char,int>('a',1)<<endl;
return 0;
}
还可以这样写在声明处定义,带默认参数的形参
#include <iostream>
using namespace std;
template<class T1,class T2=float>
T2 add(T1 x,T2 y)
{
return x+y;
}
int main()
{
cout<<add(2.1,2)<<endl;
cout<<add<>(2,2.1 )<<endl;
cout<<add<char,int>('a',1)<<endl;
cout<<add<char>('b',2.1)<<endl;
return 0;
}
自动匹配的优先级高于默认,因此模板形参的默认参数无意义。
存在即合理,当然也有他的用法,体现在这里
例:
#include <iostream>
using namespace std;
template<class T1,class T2,class T3=int>
T3 add(T1 x,T2 y)
{
return x+y;
}
int main()
{
cout<<add(2.1,2)<<endl;
cout<<add<>(2,2.1 )<<endl;
cout<<add<char,int>('a',1)<<endl;
cout<<add<char>('b',2.1)<<endl;
return 0;
}
注意返回值是T3,必须默认给T3类型,不然T3自己找不到类型。
如果不给默认类型,那么显示调用必须多给一个类型给T3。
例子:
#include <iostream>
using namespace std;
template<class T1,class T2,class T3>
T3 add(T1 x,T2 y)
{
return x+y;
}
int main()
{
cout<<add<char,int,int>('a',1)<<endl;
return 0;
}
当然模板的作用不只是俩个值相加,我们再来看看别的用法。
例设计一个通用函数,函数功能,就是为指针开辟堆区空间,空间大小由使用函数时决定。
例子
#include <iostream>
#include <assert.h>
#define max 6
using namespace std;
/*
template<class T> //模板一
T* newPoint(T ** p,int m)
{
*p=new T[m];
assert(NULL!=*p);
return *p;
}
*/
template<class T,int m>//非类型模板形参:int m,用来替换函数模板中的常量值 T:类型模板型参,替换数据类型 m:非类型模板型参,替换常量值
T * newPoint()
{
T*p=new T[m];
assert(NULL!=p);
return p;
}
int main()
{
char *p=nullptr;
//newPoint(&p,max);
//newPoint<char>(&p,max);
p=newPoint<char,max>(); //调用的是第二个函数模板,元素个数由模板形参列表中 决定
for(int i=0;i<max;i++)
{
cin>>p[i];
}
for(int i=0;i<max;i++)
{
cout<<p[i]<<" ";
}
cout<<endl;
return 0;
}
tips:
?类class模板
1.如果一个类成为了模板那么这个类中所有成员函数将自动变成函数模板
类模板函数在内部实现
#include <iostream>
using namespace std;
template<class T>
class demo//声明定义一个类模板
{
public:
demo(T x):x(x){}
void setvalue(T x)
{
this->x= x;
}
T getvalue()
{
return x;
}
private:
T x;
};
int main()
{
demo <int> obj(123);
obj.setvalue(45);
cout<<obj.getvalue()<<endl;
return 0;
}
类模板函数在外部实现
#include <iostream>
using namespace std;
template<class T>
class demo//声明定义一个类模板
{
public:
/*
demo(T x):x(x){}
void setvalue(T x)
{
this->x= x;
}
T getvalue()
{
return x;
}
*/
demo(T x);
void setvalue(T x);
T getvalue();
private:
T x;
};
template<class A>
demo<A>::demo(A x):x(x){}
template<class B>
void demo<B>::setvalue(B X)
{
this->x=X;
}
template<class C>
C demo<C>::getvalue()
{
return x;
}
int main()
{
demo <int> obj(23); //类模板定义对象时,必须显示说明使用的类模板<>,并且必须传递数据类型
obj.setvalue(45);
cout<<obj.getvalue()<<endl;
return 0;
}
类的非类型模板参数
#include <iostream>
using namespace std;
template<class T,int max>
class demo
{
public:
demo(T var);
T getval(int);
private:
T arr[max];
};
template<class A ,int max>
demo<A ,max>::demo(A var)
{
for(int i=0;i<max;i++)
{
arr[i]=var;
}
}
template<class B ,int max>
B demo<B ,max >::getval(int id)
{
if(id>=max)
{
::exit(-1);
}
return arr[id];
}
int main()
{
demo<int,6> obj(12);
int id=0;
cout<<obj.getval(id)<<endl;
return 0;
tips:
构造函数析构函数没有返回值!
友元模板
类模板的友元成员函数在类外部定义时:
1.友元成员函数的定义和声明都必须使用template关键字单独说明
#include <iostream>
using namespace std;
template<class T>
class demo
{
public:
demo(T x):x(x){}
template<class A>
friend A operator+(demo<A> &a,demo<A> &b);
/*
{
return a.x+b.x;
}
*/
private:
T x;
};
template <class A>
A operator+(demo<A> &a,demo<A> &b)
{
return a.x+b.x;
}
int main()
{
demo<int> obj(2.1),obj1(3.2);
cout<<obj+obj1<<endl;
return 0;
}
?
|