函数模板与类模板

函数模板

函数模板的概念

为了提高效率,实现代码复用,C++提供了一种处理机制,即使用函数模板。
定义函数模板的格式

template <模板参数表>
返回类型名 函数模板名(参数表)
{
  函数体的定义
}

函数模板的定义以关键字template开头,该关键字之后是使用尖括号<>括起来的”模板参数表“。

函数模板中函数体的定义方式与定义普通函数时类似。

函数模板的示例

程序9-1 定义求绝对值的函数模板并进行不同的调用

#include <iostream>
using namespace std;
template <typename T>

T abs(T x)
{
    return x<0?-x:x;
}

int main()
{
    int n = -5;
    int m = 10;
    double d = -5;
    float f = 3.2;
    cout<<n<<"的绝对值是: "<<abs(n)<<endl;
    cout<<m<<"的绝对值是: "<<abs(m)<<endl;
    cout<<d<<"的绝对值是: "<<abs(d)<<endl;
    cout<<f<<"的绝对值是: "<<abs(f)<<endl;
    return 0;
} 

-5的绝对值是: 5
10的绝对值是: 10
-5的绝对值是: 5
3.2的绝对值是: 3.2

函数指针只能指向模板的实例,而不能指向模板本身。

程序9-2 定义对象交换的函数模板

#include <iostream>
using namespace std;

template <class T>
void Swap(T &x,T &y)
{
    T tmp = x;
    x = y;
    y = tmp;
}

class myDate
{
    public:
        myDate();
        myDate(int,int,int);
        void printDate() const;
    private:
        int year,month,day;
};

myDate::myDate()
{
    year = 1970;
    month = 1;
    day = 1;
}

myDate::myDate(int y,int m,int d)
{
    year = y;
    month = m;
    day = d;
}

void myDate::printDate()const
{
    cout<<year<<"/"<<month<<"/"<<day;
    return;
}

int main()
{
    int n = 1,m = 2;
    Swap(n,m);
    double f = 1.2,g = 2.3;
    Swap(f,g);
    myDate d1,d2(2000,1,1);
    Swap(d1,d2);
    return 0;
}

显式实例化函数模板的格式

模板名 <实际类型参数1,实际类型参数2,...>

例如,程序9-2主函数中可以写成

Swap<int>(n,m);
Swap<myDate>(d1,d2);

函数模板可以带多个类型参数。

template <class T1,class T2>
void print(T1 arg1,T2 arg2)
{
  cout<<arg1<<", "<<arg2<<endl;
}

例9-1 定义对象比较的函数模板

template <typename T>
int myCompare(const T& left,const T& right)
{
  if(left<right)
  {
      return -1;
  }
  else if(right < left)
  {
    return 1;
  }
  else return 0;
}

程序9-3 对象排序程序

#include <iostream>
using namespace std;

template <typename T>
int myCompare(const T& left,const T& right)
{
  if(left<right)
  {
      return -1;
  }
  else if(right < left)
  {
    return 1;
  }
  else return 0;
}

template <class T>
void Swap(T &x,T &y)
{
    T tmp = x;
    x = y;
    y = tmp;
}

int main()
{
    string arraystring[10] = {"shang","xia","zuo","you","qian","hou","dong","xi","nan","bei"};
    int j;
    string temp;
    for(int i=1;i<10;i++)
    {
        j = i;
        while(j>0&&myCompare<string>(arraystring[j-1],arraystring[j])>0)
        {
            Swap(arraystring[j],arraystring[j-1]);
            j--;
        }
    }
    for(int i = 0;i<10;i++)
        cout<<arraystring[i]<<",";
}

bei,dong,hou,nan,qian,shang,xi,xia,you,zuo,

函数或函数模板调用语句的匹配顺序

函数模板可以重载,只要他们的形参表不同即可。

程序9-4 重载函数模板

#include <iostream>
using namespace std;

class myDate
{
    public:
        myDate();
        myDate(int,int,int);
        friend ostream & operator<<(ostream & os,const myDate & c); //友元,插入 
    private:
        int year,month,day;
};

myDate::myDate()
{
    year = 1970;
    month = 1;
    day = 1;
}

myDate::myDate(int y,int m,int d)
{
    year = y;
    month = m;
    day = d;
}

ostream & operator<<(ostream & os,const myDate & c)
{
    os<<c.year<<"/"<<c.month<<"/"<<c.day;
    return os;
}

template <class T1,class T2>
void print(T1 arg1,T2 arg2)
{
    cout<<arg1<<", "<<arg2<<endl;
}

template <class T>
void print(T arg1,T arg2)
{
    cout<<arg1<<", "<<arg2<<endl;
}

int main()
{
    int n = 1,m = 2;
    print(n,m); //输出1, 2
    myDate d1,d2(2000,1,1);
    print(d1,d2);
    print(n,d1);
    return 0; 
}

1, 2
1970/1/1, 2000/1/1
1, 1970/1/1

程序9-5 函数调用匹配顺序

#include <iostream>
using namespace std;
template <class T>
T Max(T a,T b)
{
    cout<<"Template Max 1"<<endl;
    return 0;
}

template <class T,class T2>
T Max(T a,T2 b)
{
    cout<<"Template Max 2"<<endl;
    return 0;
}

double Max(double a,double b)
{
    cout<<"Function Max"<<endl;
    return 0;
}

int main()
{
    int i=4,j=5;
    Max(1.2,3.4);
    Max(i,j);
    Max(1.2,3);
    return 0;
}

Function Max
Template Max 1
Template Max 2

类模板

当需要编写多个形式和功能都相似的类时,可以使用类模板机制。

类是对一组对象的公共性质的抽象,而类模板则是对不同类的公共性质的抽象,因此类模板是属于更高层次的抽象。

通过类模板,可以实例化一个个的类。

声明类模板的格式

template <模板参数表>
class 类模板名
{
   类体定义 
}

如果需要在类模板以外定义其成员函数,则需要采用以下格式

template <模板参数表>
返回类型名 类模板名<模板参数标识符列表>::成员函数名(参数表)
{
  函数体
}

当使用类模板创建对象时,要随类模板名给出对应于类型形参或普通形参的具体实参,格式

类模板名 <模板参数表> 对象名1,...,对象名n;

或

类模板名 <模板参数表> 对象名1(构造函数实参),...,对象名n(构造函数实参);

编译器由类模板生成类的过程称为类模板的实例化。由类模板实例化得到的类称为模板类。

类模板示例

程序9-6 类模板

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

template <class T1,class T2>
class Pair
{
    public:
        T1 first;
        T2 second;
        Pair(T1 k,T2 v):first(k),second(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    //Pair的成员函数operator<
{
    return first<p.first;   
} 

int main()
{
    Pair<string,int> student1("Tom",19);
    Pair<string,int>student2("Jim",21);
    Pair<int,int>coordinate(10,20);
    Pair<string,string>dic("word","单词");
    cout<<"学生1:"<<student1.first<<" "<<student1.second<<endl;
    cout<<"学生2:"<<student2.first<<" "<<student2.second<<endl;
    cout<<"坐标: "<<coordinate.first<<" "<<coordinate.second<<endl;
    cout<<"字典项: "<<dic.first<<" "<<dic.second<<endl;
    bool a = student1<student2;
    if(a==0)cout<<student1.first<<"位于"<<student2.first<<"之后"<<endl;
    else cout<<student1.first<<"位于"<<student2.first<<"之前"<<endl;
    return 0;
}

学生1:Tom 19
学生2:Jim 21
坐标: 10 20
字典项: word 单词
Tom位于Jim之后

程序9-7 类模板

#include <iostream>
using namespace std;
template <class T>

class TestClass
{
    public:
        T buffer[10];       //T类型的数据成员buffer数组大小固定为10
        T getData(int j);   //获取T类型buffer(数组)的第j个分量 
};

template <class T>
T TestClass<T>::getData(int j)
{
    return *(buffer+j);
}

int main()
{
    TestClass<char> ClassInstA;
    int i;
    char cArr[6] = "abcde";
    for(i=0;i<5;i++)
        ClassInstA.buffer[i] = cArr[i];
    for(i = 0;i<5;i++)
    {
        char res = ClassInstA.getData(i);
        cout<<res<<"  ";
    }
    cout<<endl;
    TestClass<double> ClassInstF;
    double fArr[6] = {12.1,23.2,34.3,45.4,56.5,67.6};
    for(i=0;i<6;i++)
        ClassInstF.buffer[i]=fArr[i]-10;
    for(i=0;i<6;i++)
    {
        double res = ClassInstF.getData(i);
        cout<<res<<"  ";
    }
    cout<<endl;
    return 0;
}

a  b  c  d  e
2.1  13.2  24.3  35.4  46.5  57.6

程序9-8 在类模板中使用函数模板

#include <iostream>
#include <string>
using namespace std;
template <class T1,class T2>
class Pair
{
    public:
        T1 first;
        T2 second;
        Pair(T1 k,T2 v):first(k),second(v){}
        bool operator<(const Pair<T1,T2>& p)const;
        template <class T>
        void print(T x)
        {
            cout<<x<<endl;
        }
};

template <class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2> & p) const    //Pair的成员函数operator<
{
    return first<p.first;   
}

int main()
{
    Pair<string,int> student1("Tom",19);
    Pair<string,int>student2("Jim",21);
    Pair<int,int>coordinate(10,20);
    Pair<string,string>dic("word","单词");
    cout<<"学生1:"<<student1.first<<" "<<student1.second<<endl;
    cout<<"学生2:"<<student2.first<<" "<<student2.second<<endl;
    cout<<"坐标: "<<coordinate.first<<" "<<coordinate.second<<endl;
    cout<<"字典项: "<<dic.first<<" "<<dic.second<<endl;
    bool a = student1<student2;
    if(a==0)cout<<student1.first<<"位于"<<student2.first<<"之后"<<endl;
    else cout<<student1.first<<"位于"<<student2.first<<"之前"<<endl;
    student1.print<string>(student1.first);
    coordinate.print<int>(coordinate.first);
    return 0;
}

学生1:Tom 19
学生2:Jim 21
坐标: 10 20
字典项: word 单词
Tom位于Jim之后
Tom
10

程序9-9 类模板中使用静态成员

#include <iostream>
using namespace std;
template <typename T>
class Test
{
    public:
        Test(T num)
        {
            k += num;
        }
        Test()
        {
            k += 1;
        }
        static void incrementK()
        {
            k += 1;
        }
        static T k;
};

template <typename T>
T Test<T>::k = 0;

int main()
{
//  static Field;
    Test<int> a;
    Test<double>b(4);
    cout<<"Test<int>::\tk="<<a.k<<endl;
    cout<<"Test<double>::\tk="<<Test<double>::k<<endl;
    Test<int> v;
    Test<double> m;
    cout<<"Test<int>::\tk="<<Test<int>::k<<endl;
    cout<<"Test<double>::\tk="<<Test<double>::k<<endl;
//  static Function
    cout<<endl;
    Test<int>::incrementK();
    cout<<"调用Test<int>::incrementK() Test<int>::k="<<Test<int>::k<<endl;
    Test<double>::incrementK();
    cout<<"调用Test<double>::incrementK() Test<double>::k="<<Test<double>::k<<endl;
    return 0;
}

Test<int>::     k=1
Test<double>::  k=4
Test<int>::     k=2
Test<double>::  k=5

调用Test<int>::incrementK() Test<int>::k=3
调用Test<double>::incrementK() Test<double>::k=6

程序9-10 使用普通参数的类模板

#include <iostream>
using namespace std;
template <int i>
class TestClass
{
    public:
        int buffer[i];
        int getData(int j);
};

template <int i>
int TestClass<i>::getData(int j)
{
    return *(buffer+j);
};

int main()
{
    TestClass<6> ClassInstF;
    int i;
    double fArr[6]={12.1,23.2,34.3,45.4,56.5,67.6};
    for(i=0;i<6;i++)
        ClassInstF.buffer[i] = fArr[i]-10;
        for(i=0;i<6;i++)
        {
            double res = ClassInstF.getData(i);
            cout<<res<<"  ";
        }
        cout<<endl;
}

2  13  24  35  46  57

类模板与继承

类模板和类模板之间、类模板和类之间可以互相继承,他们之间的常见派生关系有:

  • 普通类继承模板类。
  • 类模板继承普通类。
  • 类模板继承类模板。
  • 类模板继承模板类。

程序9-11 普通类继承模板类

#include <iostream>
using namespace std;
template<class T>
class TBase     //类模板,基类 
{
    T data;
    public:
        void print()
        {
            cout<<data<<endl;
        }
};

class Derived:public TBase<int>     //从模板类继承,普通类 
{
};

int main()
{
    Derived d;
    d.print();
}

0

程序9-12 类模板继承普通类

#include <iostream>
using namespace std;
class TBase     //基类,普通类 
{
    int k;
    public:
        void print()
        {
            cout<<"TBase::"<<k<<endl;
        }
};

template<class T>
class TDerived:public TBase     //派生类,类模板 
{
    T data;
    public:
        void setData(T x)
        {
            data = x;
        }
        void print()
        {
            TBase::print();
            cout<<"TDerived::"<<data<<endl;
        }
};

int main()
{
    TDerived<string> d;
    d.setData("2019");
    d.print();
}

TBase::1
TDerived::2019

程序9-13 类模板继承类模板

#include <iostream>
using namespace std;

template<class T>
class TBase     //类模板 
{
     T data1;
     public:
        void print()
        {
            cout<<"TBase::"<<data1<<endl;
        }
};

template <class T1,class T2>
class TDerived:public TBase<T1>     //派生类,类模板 
{
    T2 data2;
    public:
        void print()
        {
            TBase<T1>::print();
            cout<<"TDerived::"<<data2<<endl;
        }
};

int main()
{
    TDerived<int,int> d;
    d.print();
    TDerived<string,string> d2;
    d2.print();
}

TBase::0
TDerived::0
TBase::
TDerived::

程序9-14 类模板继承模板类

#include <iostream>
using namespace std;

template<class T>
class TBase
{
    T data1;
    public:
        void print()
        {
            cout<<"TBase::"<<data1<<endl;
        } 
};

template <class T2>
class TDerived:public TBase<int>
{
    T2 data2;
    public:
        void print()
        {
            TBase<int>::print();
            cout<<"TDerived::"<<data2<<endl;
        }
};

int main()
{
    TDerived<int> d;
    d.print();
    TDerived<string>d2;
    d2.print();
}

TBase::0
TDerived::0
TBase::1
TDerived::
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容