当前位置:嗨网首页>书籍在线阅读

20-模板多功能性

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

14.4.5 模板多功能性

可以将用于常规类的技术用于模板类。模板类可用作基类,也可用作组件类,还可用作其他模板的类型参数。例如,可以使用数组模板实现栈模板,也可以使用数组模板来构造数组——数组元素是基于栈模板的栈。即可以编写下面的代码:

template <typename T> // or <class T>
class Array
{
private:
    T entry;
    ...
};
template <typename Type>
class GrowArray : public Array<Type> {...}; // inheritance
template <typename Tp>
class Stack
{
      Array<Tp> ar; // use an Array<> as a component
      ...
};
...
Array < Stack<int> > asi; // an array of stacks of int

在最后一条语句中,C++98要求使用至少一个空白字符将两个>符号分开,以免与运算符>>混淆。C++11不要求这样做。

1.递归使用模板

另一个模板多功能性的例子是,可以递归使用模板。例如,对于前面的数组模板定义,可以这样使用它:

ArrayTP< ArrayTP<int,5>, 10> twodee;

这使得twodee是一个包含10个元素的数组,其中每个元素都是一个包含5个int元素的数组。与之等价的常规数组声明如下:

int twodee[10][5];

请注意,在模板语法中,维的顺序与等价的二维数组相反。程序清单14.18使用了这种方法,同时使用ArrayTP模板创建了一维数组,来分别保存这10个组(每组包含5个数)的总数和平均值。方法调用cout.width(2)以两个字符的宽度显示下一个条目(如果整个数字的宽度不超过两个字符)。

程序清单14.18 twod.cpp

// twod.cpp -- making a 2-d array
#include <iostream>
#include "arraytp.h"
int main(void)
{
    using std::cout;
    using std::endl;
    ArrayTP<int, 10> sums;
    ArrayTP<double, 10> aves;
    ArrayTP< ArrayTP<int,5>, 10> twodee;
    int i, j;
    for (i = 0; i < 10; i++)
    {
        sums[i] = 0;
        for (j = 0; j < 5; j++)
        {
            twodee[i][j] = (i + 1) * (j + 1);
            sums[i] += twodee[i][j];
        }
        aves[i] = (double) sums[i] / 10;
    }
    for (i = 0; i < 10; i++)
    {
        for (j = 0; j < 5; j++)
        {
            cout.width(2);
            cout << twodee[i][j] << ' ';
        }
        cout << ": sum = ";
        cout.width(3);
        cout << sums[i] << ", average = " << aves[i] << endl;
    }
    cout << "Done.\n";
    return 0;
}

下面是程序清单14.18所示程序的输出。在twodee的10个元素(每个元素又是一个包含5个元素的数组)中,每个元素对应于1行:列出了每个元素包含的值、这些值的总和以及平均值。

 2  3  4  5    : sum = 15,  average = 1.5
 2  4  6  8 10 : sum = 30,  average = 3
 3  6  9 12 15 : sum = 45,  average = 4.5
 4  8 12 16 20 : sum = 60,  average = 6
 5 10 15 20 25 : sum = 75,  average = 7.5
 6 12 18 24 30 : sum = 90,  average = 9
 7 14 21 28 35 : sum = 105, average = 10.5
 8 16 24 32 40 : sum = 120, average = 12
 9 18 27 36 45 : sum = 135, average = 13.5
10 20 30 40 50 : sum = 150, average = 15
Done.

2.使用多个类型参数

模板可以包含多个类型参数。例如,假设希望类可以保存两种值,则可以创建并使用Pair模板来保存两个不同的值(标准模板库提供了类似的模板,名为pair)。程序清单14.19所示的小程序是一个这样的示例。其中,方法first() const和second() const报告存储的值,由于这两个方法返回Pair数据成员的引用,因此让您能够通过赋值重新设置存储的值。

程序清单14.19 pairs.cpp

// pairs.cpp -- defining and using a Pair template
#include <iostream>
#include <string>
template <class T1, class T2>
class Pair
{
private:
    T1 a;
    T2 b;
public:
    T1 & first();
    T2 & second();
    T1 first() const { return a; }
    T2 second() const { return b; }
    Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }
    Pair() {}
};
template<class T1, class T2>
T1 & Pair<T1,T2>::first()
{
    return a;
}
template<class T1, class T2>
T2 & Pair<T1,T2>::second()
{
    return b;
}
int main()
{
    using std::cout;
    using std::endl;
    using std::string;
    Pair<string, int> ratings[4] =
    {
        Pair<string, int>("The Purpled Duck", 5),
        Pair<string, int>("Jaquie's Frisco Al Fresco", 4),
        Pair<string, int>("Cafe Souffle", 5),
        Pair<string, int>("Bertie's Eats", 3)
    };
    int joints = sizeof(ratings) / sizeof (Pair<string, int>);
    cout << "Rating:\t Eatery\n";
    for (int i = 0; i < joints; i++)
    cout << ratings[i].second() << ":\t "
         << ratings[i].first() << endl;
    cout << "Oops! Revised rating:\n";
    ratings[3].first() = "Bertie's Fab Eats";
    ratings[3].second() = 6;
    cout << ratings[3].second() << ":\t "
         << ratings[3].first() << endl;
    return 0;
}

对于程序清单14.19,需要注意的一点是,在main()中必须使用Pair<string, int>来调用构造函数,并将它作为sizeof的参数。这是因为类名是Pair<string, int>,而不是Pair。另外,Pair<char *, double>是另一个完全不同的类的名称。

下面是程序清单14.19所示程序的输出:

Rating: Eatery
5:       The Purpled Duck
4:       Jaquie's Frisco Al Fresco
5:       Cafe Souffle
3:       Bertie's Eats
Oops! Revised rating:
6:       Bertie's Fab Eats

3.默认类型模板参数

类模板的另一项新特性是,可以为类型参数提供默认值:

template <class T1, class T2 = int> class Topo {...};

这样,如果省略T2的值,编译器将使用int:

Topo<double, double> m1; // T1 is double, T2 is double
Topo<double> m2;         // T1 is double, T2 is int

第16章将讨论的标准模板库经常使用该特性,将默认类型设置为类。

虽然可以为类模板类型参数提供默认值,但不能为函数模板参数提供默认值。然而,可以为非类型参数提供默认值,这对于类模板和函数模板都是适用的。