C++面向对象程序设计之模板
1、提高程序可重用性的两种办法:
继承;
泛型程序设计(模板)
2、模板的实例化:编译器根据模板自动生成函数的过程称为模板的实例化。
一、函数的模板
3、函数模板的形式:
template<class 类型参数1,class 类型参数2,...>
返回值类型 模板名(形参表){
函数体;
};
example:
template<class T>
void Swap<T & x,T & y>
{
T temp=x;
x=y;
y=temp;
}
4、函数模板的一些特点
函数的模板中可以有不止一个类型参数
template <class T1, class T2>
T2 print(T1 arg1,T2 arg2)
{
cout<<arg1<<" "<<arg2<<endl;
return arg2;
}
example
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;
}
函数的模板可以重载,只要它们的形参表或类型参数表不同即可。
函数模板和函数的次序:
在有多个函数和函数模板名字相同的情况下,编译器如下处理一条函数调用语句
1、先找参数完全匹配的普通函数(非由模板实例化得到的函数)
2、再找参数完全匹配的模板函数
3、再找实参数经过自动类型转换后能够匹配的普通函数。
4、上面的都找不到,则报错。
注意:在匹配模板函数时,不进行类型自动转换
template<class T>
T myFunction(T arg1,T arg2)
{
cout<<arg1<<" "<<arg2<<"\n";
return arg1;
}
myFunction(5,7);//ok
myFunction(5.8,8.4);//ok
myFunction(5,8.4);//error
综合实例:
#include<iostream>
using namespace std;
template<class T,class Pred>
void Map(T s,T e,T x,Pred 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];
double d[5]={1.1,2.1,3.1,4.1,5.1},c[5];
int main(){
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;
return 0;
}
二、类的模板
2.1 主要目标:定义一批相似的类,可以通过定义类模板然后由类模板生成不同的类。
2.2 类模板定义的两种方式:
template<class 类型参数为,class 类型参数2,......>//类型参数表
class 类模板名
{
成员函数和成员变量;
};
template<typename 类型参数为,typename 类型参数是,......>//类型参数表
class 类模板名
{
成员函数和成员变量;
};
其实typename和class是等价的,用那个都行。
2.3 类模板中成员函数的写法:
template<class 类型参数1,class 类型参数2,...>//类型参数表
返回值类型 类模板名 <类型参数名列表>::成员函数名(形参数表)
{
................
}
2.4 类模板定义对象的写法:
类模板名<真实类型参数表> 对象名(构造函数实参表);
example
template<class T1,class 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
{
return key<p.key;
}
};
int main()
{
Pair<string,int>student("Tom",19);
cout<<student.key<<" "<<student.value;
return 0;
}
用类模板定义对象
编译器由类模板生成类的过程叫类模板的实例化。
由类模板实例化得到的类,叫模板类。
同一个类模板的两个模板类是不兼容的。
Pair<string,int>*p;
Pair<string,double>a;
p=&a;//wrong
2.5 函数模板作为类模板成员
#include<iostream>
using namespace std;
template <class T>
class A
{
public:
template<class T2>
void Func(T2 t){cout<<t;}//成员函数模板
};
int main()
{
A<int>a;
a.Func('K');//成员函数模板被实例化
a.Func("hello");//
return 0;
}
2.6 类模板与非类型参数
类模板的“<类型参数表>”中可以出现非类型参数
template <clas T,int size>
Class CArray{
T array[size];
public:
void Print()
{
for(int i=0;i<size;++i)
cout<<array[i]<<endl;
}
};
CArray<double,40>a2;
CArray<int,50>a3;
三、类模板与派生
1、类模板派生的四种方式:
//类模板从类模板派生;
//类模板从模板类派生;
//类模板从普通类派生;
//普通类从模板类派生;
1.1 类模板从类模板派生
template <class T1,class T2>
class A{
T1 v1;T2 v2;
};
template <class T1,class T2>
class B:public A<T2,T1>{
T1 v3; T2 v4;
}
template<class T>
class C:public B<T,T>{
T v5;
}
int main()
{
B<int,double> obj1;
C<int> obj2;
return 0;
}
1.2 类模板从类模板派生
template <class T1,class T2>
class A{
T1 v1;T2 v2;
};
template <class T>
class B:public A<int,double>{
T v;
};
int main(){
B<char> obj1;//自动生成两个模板类:A<int,double>和B<char>
return 0;
}
1.3类模板从普通类派生
class A{
int v1;
};
template<class T>
class B:public A{//所有从B实例化得到的类,都以A为基类
T v;
};
int main()
{
B<char> obj1;
return 0;
}
1.4 普通类从模板类派生
template <class T>
class A{
T v1;
int n;
};
class B:public A<int>{
double v;
};
int main(){
B obj1;
return 0;
}
四、类模板与友元
函数、类、类的成员函数作为类模板的友元;
函数模板作为类模板的友元;
函数模板作为类的友元;
类模板作为类模板的友元;
4.1 函数、类、类的成员函数作为类模板的友元
void Func1(){}
class A{};
class B{
public:
void Func(){}
};
template <class T>
class Tmpl
{
friend void Func1();
friend class A;
friend void B::Func();
};//任何从Tmpl1实例化来的类,都有以上三个友元
4.2 函数模板作为类模板的友元