C++Primer Plus 第十四章代码重用:14.4.4 数组模板示例和非类型参数

系列文章目录

` 14.4.4 数组模板示例和非类型参数


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


14.4.4 数组模板示例和非类型参数

模板常用作容器类,这是因为类型参数的概念非常适合于将相同的存储方案用于不同的类型。确实,为容器类提供可重用代码是引入模板的主要动机,所以我们来看看另一个例子,深入探讨模板设计和使用的其他几个方面。具体地说,将探讨一些非类型(或表达式)参数以及如何使用数组来处理继承族。首先介绍一个允许指定数组大小的简单数组模板。一种方法是在类中使用动态数组和构造函数参数来提供元素数目,最后一个版本的 Stack模板采用的就是这种方法。另一种方法是使用模板参数来提供常规数组的大小,C++11新增的模板 array 就是这样做的。程序清单 14.17 演示了如何做。
程序清单 14.17arraytp.h

//arraytp.h  -- Array Template
#ifndef ARRAYTP_H_
#define ARRAYTP_H_

#include <iostream>
#include <cstdlib>

template <class T, int n>
class ArrayTP
{
private:
    T ar[n];
public:
    ArrayTP() {};
    explicit ArrayTP(const T & v);
    virtual T & operator[](int i);
    virtual T operator[](int i) const;
};

template <class T, int n>
ArrayTP<T,n>::ArrayTP(const T & v)
{
    for (int i = 0; i < n; i++)
        ar[i] = v;
}

template <class T, int n>
T & ArrayTP<T,n>::operator[](int i)
{
    if (i < 0 || i >= n)
    {
        std::cerr << "Error in array limits: " << i
            << " is out of range\n";
        std::exit(EXIT_FAILURE);
    }
    return ar[i];
}

template <class T, int n>
T ArrayTP<T,n>::operator[](int i) const
{
    if (i < 0 || i >= n)
    {
        std::cerr << "Error in array limits: " << i
            << " is out of range\n";
        std::exit(EXIT_FAILURE);
    }
    return ar[i]; 
}

#endif

请注意程序清单 14.17中的模板头:

template <class T,int n>

关键字 class(或在这种上下文中等价的关键字 typename)指出T为类型参数,int指出n的类型为 int。这种参数(指定特殊的类型而不是用作泛型名)称为非类型(non-type)或表达式(expression)参数。假设有下面的声明:

ArrayTP<double,12>eggweights;

这将导致编译器定义名为 ArrayTP<double,12>的类,并创建一个类型为ArrayTP<double,12>的eggweight对象。定义类时,编译器将使用double 替换 T,使用12替换 n。
表达式参数有一些限制。表达式参数可以是整型、枚举、引用或指针。因此,doublem是不合法的,但 doublemm 和 doublepm 是合法的。另外,模板代码不能修改参数的值,也不能使用参数的地址。所以,在 ArayTP模板中不能使用诸如 n++和&n等表达式。另外,实例化模板时,用作表达式参数的值必须
是常量表达式。与Stack中使用的构造函数方法相比,这种改变数组大小的方法有一个优点。构造函数方法使用的是通过 new 和 delete 管理的堆内存,而表达式参数方法使用的是为自动变量维护的内存栈。这样,执行速度将更快,尤其是在使用了很多小型数组时。
表达式参数方法的主要缺点是,每种数组大小都将生成自己的模板。也就是说,下面的声明将生成两个独立的类声明:

ArrayTP<double,12>eggweights;ArrayTP<double,13>donuts;

但下面的声明只生成一个类声明,并将数组大小信息传递给类的构造函数:

Stack<int>eggs(12);
Stack<int>dunkers(13);

另一个区别是,构造函数方法更通用,这是因为数组大小是作为类成员(而不是硬编码)存储在定义中的。这样可以将一种尺寸的数组赋给另一种尺寸的数组,也可以创建允许数组大小可变的类。


  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值