面向对象与C++程序设计-函数模板与类模板学习笔记

来源:互联网 发布:淘宝上小提琴教学视频 编辑:程序博客网 时间:2024/06/07 09:00

函数模板

概念

函数模板( function template) 是一个独立于类型的函数, 可作为
一种模式, 产生函数的特定类型版本

函数模板定义的语法形式为:

template<模板形参表>返回类型 函数名(形参列表){函数体}

模板形参表

模板形参表( template parameter list) 是用一对尖括号括< >括起
来的一个或多个模板形参的列表, 不允许为空, 形参之间以逗号分
隔, 其形式有两种。
第一种形式:

typename 类型参数名1,typename 类型参数名2,......

第二种形式

class 类型参数名1, class 类型参数名2,......
创建一个函数模板Max( ),该模板返回两个参数中的最大值:
#include <iostream>#include <string>using namespace std;template <class T>T Max(T i, T j){    return (i > j) ? i : j;}int main(){    int m, n;    char c, d;    string s1, s2;    cin >> m >> n;    cin >> c >> d;    cin >> s1 >> s2;    cout << Max(m, n) << endl;    cout << Max(c, d) << endl;    cout << Max(s1, s2) << endl;    return 0;}
创建一个函数模板实现求数组中的最小元素,在主函数将分别使用该模板求整形数组和double型数组中的最小元素并输出:
#include <iostream>using namespace std;template <class T>T Min(T *p, int len){    int i,j;    T x;    for (i = 0; i < len-1;i++)        for (j = 0; j < len-i-1;j++)            if (p[j + 1] < p[j])            {                x = p[j+1]; p[j + 1] = p[j]; p[j] = x;            }    return *p;}int main(){    int n, m, *pn, i = 0;    cin >> n;    pn = new int[n];    do{        cin >> pn[i];        i++;    } while (i<n);    double *pd;    i = 0;    cin >> m;    pd = new double[m];    do{        cin >> pd[i];        i++;    } while (i<m);    cout << Min(pn, n) << endl;    cout << Min(pd, m) << endl;    delete[] pn;    delete[] pd;    return 0;}

执行情况:

6 (输入整型数组中的元素个数)8 3 4 1 6 9 (输入整型数组中的元素)5 (输入双精度浮点数数组中的元素个数)2.7 3.1 9.8 5.3 7.6 (输入双精度浮点数数组中的元素)输出:12.7

类模板

定义的一般形式为:

template <模板形参表>class 类模板名 {//类体成员列表};

模板形参表

是用一对尖括号< >括住的一个或多个模板形参的列表, 不允许为
空, 形参之间以逗号分隔。 其一般形式为:

<class 类型参数1, class 类型参数2, ...... >

模板形参表用于表示可以在类定义中使用的数据类型。 类型形参跟
在关键字class或typename之后定义, 如class T是名为T的类型形参,
在这里class和typename没有区别。 一般地, 类模板习惯用class,
函数模板习惯用typename

例如定义一个类模板表示平面上的点:

template <class T> //类模板定义class Point { //Point不是类名是模板名public:Point() : x(0), y(0) { } //默认构造函数Point(const T a, const T b) : x(a), y(b) { } //带参数构造函数void Set(const T a, const T b);void Display(){ cout<<"Display: "<<"x="<<x<<",y="<<y<<endl; }private:T x, y;};

如果在类模板外部定义成员函数, 形式为:

template <模板形参表>返回类型 类名<类型参数表>::函数名(形式参数列表){函数体}

例如:

template <模板形参表>返回类型 类名<类型参数表>::函数名(形式参数列表){函数体}

用类模板定义对象时, 必须为模板形参显式指定类型实参, 一般形式为:

类模板名<类型实参表> 对象名列表;类模板名<类型实参表> 对象名1(实参列表1), 对象名2(实参列表2),......;

例如:

Point <int> a, b; //定义类模板对象, 调用默认构造函数Point <double> m(1,2), n(3,4); //定义类模板对象 , 调用带参数构造函数

模板形参表还可以是非类型形参, 其形式与函数形参表相似。 例如:

template <class T, int N>class Sequence { //Sequence类模板public:void Set(int i, T value);T Get(int i) { return array[i]; }private:T array[N];};template <class T, int N>void Sequence<T,N>::Set(int i, T value){ array[i]=value; }

当定义类模板对象时, 必须为每个非类型形参提供常量表达式以供使用。 例如:

Sequence <int,5> a; //提供类型和常量表达式Sequence <double,5> b; //提供类型和常量表达式for(i=0;i<5;i++) a.Set(i,i); //给a的数组成员赋值for(i=0;i<5;i++) cout<<a.Get(i)<<" "; //输出数组成员的值

模板形参还可以设置默认值。 例如:

template <class T=char , int N=10> //类模板定义class Sequence {…};

则对象定义时可以有以下形式:

Sequence <> m; //使用默认类型char和使用默认值10Sequence <double> n; //提供类型和使用默认值10Sequence <int,100> k; //提供类型和常量表达式

关键字export

函数模板或类模板的实例化与定义体可以不必放在同一个编
译单元

标准C++为此提供了关键字export, 其作用与extern相似, 例如:

extern int n; //声明整型n, 变量定义在另一个编译单元extern struct Point p; //实例化结构体对象p, 结构体定义在另一个编译单元extern class Stack s; //实例化类对象s, 类定义在另一个编译单元export template<class T>class A<int> a; //实例化类模板对象s, 类模板定义在另一个编译单元export template<class T>void f (T& t);//实例化函数模板f,函数模板定义在另一个编译单元

类模板在表示数组、 向量、 列表、 队列、 栈、 矩阵等数据结构时,显得特别重要, 因为这些数据结构的表示和算法的选择不受其所包含的元素的类型的影响

一个简单的队列类模板练习:

请按照下列简单的整数队列类创建一个简单的队列类模板。
整数队列类如下:

const int SIZE=100;//整数队列类class Queue {      int q[SIZE];  int front;  //队列头  int rear;   //队列尾public:  Queue( )   { front = rear = 0; }  void put(int i); // 在队尾放置一个数据  int get( );  // 从队列头部取一个数据};

裁判测试程序样例:

在这里给出函数被调用进行测试的例子。例如:#include <iostream>#include <string>using namespace std;// 你提交的代码将嵌入到这里int main(){  Queue<int> a; // 创建一个整数队列  int m,n;  cin>>m>>n;   a.put(m);  a.put(n);  cout << a.get() << " ";  cout << a.get() << endl;  Queue<double> d; // 创建一个双精度浮点数队列  double x,y;  cin>>x>>y;  d.put(x);  d.put(y);  cout << d.get() << " ";  cout << d.get() << endl;  Queue<string> qs;// 创建一个字符串队列  string s1,s2,s3;  cin>>s1>>s2>>s3;  qs.put(s1);  qs.put(s2);  qs.put(s3);  cout <<               qs.get() << " ";  cout <<               qs.get() << " ";  cout << qs.get() << endl;  return 0;}

输入样例:

6 93.14159 2.781828ShenZhen Beijing HangZhou

输出样例:

6 93.14159 2.78183ShenZhen Beijing HangZhou

目标代码:

const int SIZE = 100;template <class T>class Queue {    T q[SIZE];    int front;  //队列头    int rear;   //队列尾public:    Queue()    {        front = rear = 0;    }    void put(T i); // 在队尾放置一个数据    T get();  // 从队列头部取一个数据};template <class T>void Queue<T>::put(T i){    if (front == SIZE)    {        cout << "队列已满" << endl;        exit(1);    }    rear++;    q[rear] = i;}template<class T>T Queue<T>::get(){    if (front == rear)    {        cout << "队列空" << endl;    }    front++;    return q[front];}
0 0