学而时习之:C++中的标准模板库2

33 阅读2分钟

C++ 中的泛型

泛型(Generics)是指把“类型”(如 Integer、String 以及用户自定义类型)作为参数传给方法、类或接口的一种机制。例如,数组、映射等容器都可以通过泛型高效地复用于任意类型。泛型编程的核心目标是提升代码效率:只需编写一次通用算法,就能自动适用于所有数据类型,无需为整型、字符串、字符等分别实现不同版本。

泛型的优势:

  • 代码可复用
  • 避免函数重载
  • 一次编写,多次/多场景使用

在 C++ 中,泛型通过 模板(Templates) 实现。模板是一种简单却极其强大的机制:把“数据类型”当作参数传递,从而避免为不同类型重复编写相同代码。

例如,一家软件公司需要针对多种数据类型实现 sort(),与其维护多份代码,不如写一份模板 sort(),然后把具体类型作为参数传入即可。

使用模板的泛型函数:

我们可以写一个“通用函数”,让它自动适用于不同的数据类型。典型的例子有 sort()max()min()printArray() 等。

#include <iostream>
using namespace std;

// 一份代码,所有类型都能用。
template <typename T>
T myMax(T x, T y)
{
    return (x > y) ? x : y;
}

int main()
{
    // 用 int 类型调用 myMax
    cout << myMax<int>(3, 7) << endl;

    // 用 double 类型调用 myMax
    cout << myMax<double>(3.0, 7.0) << endl;

    // 用 char 类型调用 myMax
    cout << myMax<char>('g', 'e') << endl;

    return 0;
}
7
7
g

使用模板的泛型类:

与函数模板类似,当类所描述的功能与具体数据类型无关时,就可以用类模板。典型的例子有链表、二叉树、栈、队列、数组等。下面给出一个简单的“模板数组”示例。

#include <iostream>
using namespace std;

template <typename T>
class Array {
private:
    T* ptr;     // 指向动态数组的指针
    int size;   // 数组元素个数

public:
    Array(T arr[], int s);  // 构造函数
    void print();           // 打印数组内容
};

// 类外定义构造函数
template <typename T>
Array<T>::Array(T arr[], int s)
{
    ptr = new T[s];      // 动态分配内存
    size = s;
    for (int i = 0; i < size; i++){
        ptr[i] = arr[i]; // 拷贝元素
    }
}

// 类外定义打印函数
template <typename T>
void Array<T>::print()
{
    for (int i = 0; i < size; i++){
        cout << " " << *(ptr + i);
    }
    cout << endl;
}

int main()
{
    int arr[5] = { 1, 2, 3, 4, 5 };
    Array<int> a(arr, 5);  // 用 int 类型实例化 Array 模板
    a.print();             // 输出数组内容
    return 0;
}
 1 2 3 4 5

多类型泛型(模板多个类型参数)

模板可以一次性接受不止一个类型参数。下面示例展示了如何向模板传递两种甚至更多数据类型。

#include <iostream>
using namespace std;

template <class T, class U>   // 两个类型参数 T 和 U
class A {
    T x;   // 类型为 T 的成员
    U y;   // 类型为 U 的成员

public:
    A()    // 构造函数
    {
        cout << "Constructor Called" << endl;
    }
};

int main()
{
    A<char, char> a;    // T=char, U=char
    A<int, double> b;   // T=int, U=double
    return 0;
}
Constructor Called
Constructor Called