2025年3月23日 星期日 甲辰(龙)年 月廿二 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > VC/VC++

C++类模板用法详解

时间:03-07来源:作者:点击数:72

如果需要的多个函数具有相同的解决问题的逻辑,只是它们所使用的形参的类型不同,则可以使用函数模板。同样,如果需要的多个类仅在其某些数据成员的类型方面有所不同,或者仅在其成员函数的形参类型方面有所不同,则都可以使用类模板

声明一个类模板和声明一个函数模板类似,可以使用诸如 T、T1、T2 之类的标识符(或者由程序员选择的任何其他标识符)作为泛型来编写类,然后使用正确编写的模板头作为类声明的前缀。

例如,假设要定义一个类,用来表示一个泛型类型的数组,并添加一个重载运算符 [] 以执行边界检查,则可以定义 SimpleVector 类,并输入适当的数据成员和构造函数,按以下方式编写模板:

  • template<class T>
  • class SimpleVector
  • {
  • unique_ptr<T []>aptr;
  • int arraysize;
  • public:
  • SimpleVector (int) ; // 构造函数
  • SimpleVector (const SimpleVector &) ; // 复制构造函数
  • int size () const{ return arraySize; }
  • T &operator [] (int) ; // 重载[]运算符
  • void print () const; // 输出数组元素
  • };

这个类模板将把类型 T 的元素存储在一个动态生成的数组中。这就解释了为什么指向这个数组底部的指针 aptr 被声明为 T[] 类型的指针。这里使用了 unique_ptr 独占指针作为 aptr 的类型,因为 SimpleVector 对象将不会和程序的其他部分共享动态分配的数组。

同样,重载的数组下标运算符返回一个 T 类型的值。但需要注意的是,size 成员函数返回的值和表示存储在数组中的元素数量的成员 armySize 都是 int 类型。这是有道理的,因为无论数组存储的元素数据是什么类型,数组中元素的数量总是一个整数。

可以将 SimpleVector 模板看作一种通用模式,通过对它进行特殊化即可创建多个不同的 SimpleVector 类,以保存 double、long、string 或任何其他可以定义的类型。规则是在类模板的名称 SimpleVector 后面附加一个实际类型的列表(以尖括号括起来),从而形成一个实际的类的名称,示例如下:

  • SimpleVector <double> 是存储 double 数组的类的名称。
  • SimpleVector <string> 是存储 string 数组的类的名称。
  • SimpleVector <char> 是存储 char 数组的类的名称。

现在来看一个定义 SimpleVector 对象的示例,它通过使用转换构造函数创建了一个包含 10 个 double 类型元素的数组。

SimpleVector <double> dTable(10);

在类中定义一个模板类的成员函数是很简单的,例如,在 SimpleVector 类中即可轻松定义 size() 函数。但是,如果要在类的外面定义成员函数,则必须使用模板头来给成员函数的定义添加前缀(该模板头指定了类型形参的列表),然后在定义中还需要使用类模板的名称,后面还要跟着一个类型形参的列表(使用尖括号括起来)。

现在使用运算符 [] 函数来说明如何在类外部定义成员函数:

  • template<class T>
  • T &SimpleVector<T>::operator[](int sub)
  • {
  • if(sub < 0 || sub >= arraySize)
  • throw IndexOutOfRangeException(sub)
  • return aptr[sub];
  • }

在这个定义中,由于作用域解析运算符(::)之前需要类的名称,所以在该位置添加了 SimpleVector <T>。以下是另外一个示例,它是转换构造函数的定义:

  • template<class T>
  • SimpleVector<T>::SimpleVector(int s)
  • {
  • arraySize = s;
  • aptr = make_unique<T[]> (s);
  • for (int count = 0; count < arraySize; count++)
  • aptr[count] = T();
  • }

在该示例中,需要在作用域解析运算符之前有 SimpleVector <T>,但是在作用域解析运算符之后,却只有 SimpleVector,而没有 <T>,这是因为在作用域解析运算符后面需要的不是类的名称,而是成员函数的名称,在这种情况下恰好是构造函数。

将类型形参列表附加到模板类名称的规则有一个例外。只要该类的名称在模板类的作用域内,则该列表和包含它的尖括号就可以省略。因此,当一个类的名称在类本身的任何地方被使用,或者位于被定义在类之外的成员函数的局部作用域内时,该列表即可被省略。

例如,来看以下复制构造函数:

  • template<class T>
  • SimpleVector<T>::SimpleVector(const SimpleVector &obj)
  • {
  • arraySize = obj.arraySize;
  • aptr = make_unique<T []>(arraySize);
  • for (int count = 0; count < arraySize; count++)
  • aptr[count] = obj[count];
  • }

该函数就不需要将 <T> 附加到 SimpleVector 以表示其参数类型。

SimpleVector 的转换构造函数假定类型形参T在执行赋值语句 "aptr[count] = T();" 时有一个默认的构造函数 T()。如果T是基础类型,则 C++ 编译器将使用默认值 0 替换 T()。例如,如果 T 是 int,那么该赋值语句相当于 aptr[count] = int(),并且值 0 将被存储在 aptr[count] 中。

SimpleVector 模板的代码在 SimpleVector.h 文件中列出。

  • //SimpleVector.h
  • #include <iostream>
  • #include <cstdlib>
  • #include <memory>
  • using namespace std;
  • // Exception for index out of range
  • struct IndexOutOfRangeException
  • {
  • const int index;
  • IndexOutOfRangeException(int ix) :
  • index(ix) {}
  • };
  • template <class T>
  • class SimpleVector
  • {
  • unique_ptr<T []> aptr;
  • int arraySize;
  • public:
  • SimpleVector(int); // Constructor
  • SimpleVector(const SimpleVector &); // Copy constructor
  • int size() const { return arraySize; }
  • T &operator[](int); // Overloaded [] operator
  • void print () const; // outputs the array elements
  • };
  • template <class T>
  • SimpleVector<T>::SimpleVector(int s)
  • {
  • arraySize = s;
  • aptr = make_unique<T[]>(s);
  • for (int count = 0; count < arraySize; count++)
  • aptr[count] = T();
  • }
  • template <class T>
  • SimpleVector<T>::SimpleVector(const SimpleVector &obj)
  • {
  • arraySize = obj.arraySize;
  • aptr = make_unique<T[]>(obj.arraySize);
  • for (int count = 0; count < arraySize; count++)
  • aptr[count] = obj[count];
  • }
  • template <class T>
  • T &SimpleVector<T>::operator[](int sub)
  • {
  • if (sub < 0 || sub >= arraySize)
  • throw IndexOutOfRangeException(sub);
  • return aptr[sub];
  • }
  • template <class T>
  • void SimpleVector<T>::print() const
  • {
  • for (int k = 0; k < arraySize; k++)
  • cout << aptr [k] << " ";
  • cout << endl;
  • }

下面的程序演示了 SimpleVector 模板的使用:

  • //This program demonstrates the SimpleVector template.
  • #include <iostream>
  • #include "SimpleVector.h"
  • using namespace std;
  • int main()
  • {
  • const int SIZE = 10;
  • SimpleVector<int> intTable (SIZE);
  • SimpleVector<double> doubleTable(SIZE);
  • // Store values in the arrays
  • for (int x = 0; x < SIZE; x++)
  • {
  • intTable[x] = (x * 2);
  • doubleTable[x] = (x * 2.14);
  • }
  • // Display the values in the arrays
  • cout << "These values are in intTable:\n";
  • intTable.print();
  • cout << "These values are in doubleTable:\n";
  • doubleTable.print ();
  • // Use the built-in + operator on array elements
  • for (int x = 0; x < SIZE; x++)
  • {
  • intTable[x] = intTable[x] + 5;
  • doubleTable[x] = doubleTable[x] + 1.5;
  • }
  • // Display the values in the array
  • cout << "These values are in intTable:\n";
  • intTable.print ();
  • cout << "These values are in doubleTable:\n"; doubleTable.print ();
  • // Use the built-in ++ operator on array elements
  • for (int x = 0; x < SIZE; x++)
  • {
  • intTable[x]++;
  • doubleTable[x]++;
  • }
  • // Display the values in the array
  • cout << "These values are in intTable:\n";
  • intTable.print ();
  • cout << "These values are in the doubleTable: \n";
  • doubleTable.print();
  • cout << endl;
  • return 0;
  • }

程序输出结果:

These values are in intTable:
0 2 4 6 8 10 12 14 16 18
These values: are in doubleTable:
0 2.14 4.28 6.42 8.56 10.7 12.84 14.98 17.12 19.26
These values are in intTable:
5 7 9 11 il3 15 17 19 21 23
These values are in doubleTable:
1.5 3.64 5.78 7.92 10.06 12.2 14.34 16.48 18.62 20.76
These values are in intTable:
6 8 .10 12 14 16 18 20 22 24
These values are in the doubleTable:
2.5 4.64 6.78 8.92 11.06 13.2 15.34 17.48 19.62 21.76

注意,在包含驱动模块代码的文件中已经 include 包含模板代码的文件,这样可以避免单独链接已编译的使用模板的文件,降低复杂性。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门