C++模板:函数模板、类模板

C++ 模板是一种强大的特性,它允许程序员编写泛型代码,即在编写代码时不指定具体的数据类型,而是在使用模板时再确定类型。以下是关于C++模板的详细介绍:

一、函数模板

函数模板是一种通用的函数定义,可以用于处理不同类型的数据,只要这些类型支持模板函数内部操作所需的操作符或成员函数。

函数模板的定义以关键字template开始,后面跟着一个或多个模板参数,这些参数通常是类型参数,用尖括号<>括起来。

下面是一个简单的函数模板,用于交换两个变量的值:

template <typename T>
void swap(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

在这个例子中,typename T 声明了一个类型参数T,函数swap可以用于交换任何类型T的两个变量的值,只要类型T支持赋值操作。

使用函数模板时,编译器会根据传入的实际参数类型自动生成相应的函数实例。例如:

int main() {
    int num1 = 5, num2 = 10;
    swap(num1, num2);
    double num3 = 3.14, num4 = 2.71;
    swap(num3, num4);
    return 0;
}

当调用swap(num1, num2)时,编译器会生成一个swap函数的实例,其中T被替换为int类型;当调用swap(num3, num4)时,T被替换为double类型。

二、类模板

类模板与函数模板类似,但它是用于创建泛型类的。类模板可以包含成员变量、成员函数等,这些成员的类型可以是模板参数类型。

以下是一个简单的类模板示例,用于表示一个动态大小的数组:

template <typename T, int size>
class Array {
    public:
        Array() {}
        T& operator[](int index) {
            return data[index];
        }
    private:
        T data[size];
};

在这个类模板中,有两个模板参数:typename T 表示数组中元素的类型,int size 表示数组的大小。

使用类模板时,需要指定模板参数。例如:

int main() {
    Array<int, 5> intArray;
    intArray[0]=1;
    Array<double, 3> doubleArray;
    doubleArray[1] = 3.14;
    return 0;
}

这里创建了两个不同类型的Array类实例:intArray是一个包含5个int元素的数组,doubleArray是一个包含3个double元素的数组。

三、模板的特化

模板特化是指为特定的模板参数类型提供专门的模板实现。当使用这些特定类型时,编译器会优先使用特化的模板版本,而不是通用的模板版本。

假设我们有一个函数模板用于比较两个数的大小:

template <typename T>
bool compare(T a, T b) {
    return a < b;
}

对于const char*类型(C - 风格字符串),上面的通用模板实现可能不符合预期,因为直接比较指针的值并不能比较字符串的实际内容。所以我们可以对const char*类型进行特化:

template <>
bool compare<const char*>(const char* a, const char* b) {
    return strcmp(a, b)<0;
}

在这个特化版本中,我们使用strcmp函数来比较两个C - 风格字符串的实际内容。

四、模板的优势

1. 代码复用

通过编写通用的模板代码,可以避免为不同类型编写重复的函数或类。例如,不需要为int、double、float等类型分别编写交换函数,一个函数模板就可以满足需求。

2. 类型安全

模板是类型安全的,因为编译器会根据实际使用的类型生成相应的代码。如果类型不支持模板内部所需的操作,编译器会在编译时检测到错误。

3. 灵活性和可扩展性

可以方便地添加新的类型支持,只需要满足模板内部操作的要求即可。并且可以通过模板特化来处理特定类型的特殊情况。

C++编程语言基础

C++模板:函数模板、类模板