首页 > 编程笔记 > C++笔记 阅读:73

C++函数模板和类模板的用法(附带实例)

C++11 和之前的版本中模板主要分成两种,一种是函数模板,另一种是类模板。

C++ 函数模板允许编写可以适用于不同类型的函数。函数模板是通过模板定义关键字 template 和泛型参数来定义的,这些泛型参数可以在用来修饰函数的参数列表、返回类型或函数体中使用。

看一个简单的 C++ 函数模板示例,代码如下:
#include<iostream>

template<typename T>
T max(T a,T b){ return(a > b)?a : b;}

int main()
{
    int x  = 5,y  = 10;
    float p  = 3.14, q  = 2.7;
    //max()函数被实例化成int max(int a,int b)的形式
    std::cout<< max(x,y)<< std::endl;   //输出10
    //max()函数被实例化成int max(float a,float b)的形式
    std::cout<< max(p,q)<< std::endl;   //输出3.14
    return 0;
}
运行结果为:

10
3.14

在上述示例中,max() 函数是一个函数模板,并使用 typename 关键字定义了一个模板参数 T,在实际使用时是一种类型,如此也就将数据的类型进行参数化了。这允许 max() 函数在编译时对不同类型的参数进行实例化。通过比较两个参数的大小,max() 函数将返回较大值。

在 main() 函数中,max() 函数被分别实例化为处理 int 和 float 类型的版本。在这种情况下,编译器会根据函数模板的定义自动生成适当的函数实现。

函数模板也可以包含多个模板参数,并且可以应用于其他函数特性,如默认参数、重载和特化。例如,可以定义一个函数模板来计算数组的平均值,代码如下:
template<typename T,int size>
double average(T arr[size])
{
    double sum  = 0;
    for(int i  = 0;i < size;i ++){
        sum + = arr[i];
    }
    return sum/size;
}
通过函数模板,可以提高代码的重用性和灵活性。使用函数模板来定义可以处理不同类型任务的函数,从而避免编写多个具有相似功能的函数。

C++类模板

类模板允许编写可以适用于不同数据类型的类。类模板是通过模板关键字 template 和泛型参数来定义的,这些参数可以在类的成员变量、成员函数或类体中使用。

定义类的模板可以使用 class,也可以使用 struct。下面是一个简单的 C++ 类模板示例,代码如下:
#include <iostream>
#include <string>
// 为了使用 string 类型,包含该头文件

template <typename T>
class Stack
{
private:
    T* data;
    int size;
    int capacity;

public:
    // 构造函数,初始化容量、大小,分配内存
    Stack(int cap) : capacity(cap), size(0)
    {
        data = new T[capacity];
    }

    // 析构函数,释放动态分配的内存,防止内存泄漏
    ~Stack()
    {
        delete[] data;
    }

    void push(T element)
    {
        if (size < capacity) {
            data[size++] = element;
        }
    }

    T pop()
    {
        if (size == 0) {
            // 这里根据 T 类型合理返回“空”值,对于基本类型可返回默认构造值,复杂类型可抛异常等,这里简单处理
            return T();
        }
        return data[--size];
    }

    bool isEmpty()
    {
        return size == 0;
    }
};

int main()
{
    // 实例化成整型数的 Stack
    Stack<int> intStack(5);
    intStack.push(1);
    intStack.push(2);
    intStack.push(3);
    std::cout << intStack.pop() << std::endl;      // 输出 3

    // 实例化成 std::string 的 Stack
    Stack<std::string> stringStack(5);
    stringStack.push("hello");
    stringStack.push("world");
    std::cout << stringStack.pop() << std::endl;   // 输出 world

    return 0;
}
运行结果为:

3
world

在上述示例中,Stack 类被声明为一个类模板,并使用 typename 关键字定义了一个模板参数 T,允许 Stack 类在编译时对不同类型的数据进行实例化。

在 main() 函数中,Stack 类被分别实例化为处理 int 和 std::string 类型的版本。在这种情况下,编译器会根据类模板的定义自动生成适当的类实现。通过模板参数实现了一次编码的模块能够适用多种不同数据类型的情况。

类模板也可以包含多个模板参数,并且可以应用于其他类特性,如继承、成员模板和特化。通过类模板,可以提高代码的重用性和灵活性。使用类模板来定义可以处理不同类型任务的类,从而避免编写多个具有相似功能的类。

从 C++11 开始支持了可变模板参数,使模板参数的个数可以不确定。变长参数被折叠成一个参数包,使用的时候通过迭代展开或者使用新增的 std::tuple 展开。

需要注意的是,不论是函数模板还是函数类模板在进行具体实例的操作时都是在编译的过程中进行的,一旦编译过程中确定了,参数在运行期是不可以进行多态化的,所以 C++ 的模板是一种静态的多态化。在编译的过程中对数据类型进行多态化,而 C++ 的虚函数则是对行为进行多态化。

C++模板参数

模板参数是在编写泛型代码时使用的特殊参数类型。使用模板参数可以在编译时将类型作为参数传递给模板,从而在编写代码时可以处理不同类型的数据。

在 C++ 中,有两种类型的模板参数,即类型模板参数和非类型模板参数。类型模板参数允许在模板中使用不同的数据类型,代码如下:
template<typename T>
void swap(T&a,T&b)
{
    T temp = a;
    a = b;
    b = temp;
}
在上面的示例中,T 是一种类型模板参数,它允许在编写代码时使用不同的数据类型来调用 swap() 函数。

非类型模板参数允许在模板中使用常量表达式作为参数,代码如下:
template<int SIZE>
struct Buffer
{
    int data[SIZE];
};
在上面的示例中,SIZE 是一个非类型模板参数,可以在编写代码时指定 Buffer 结构体中的数组大小。

通过模板参数可以编写更通用、更灵活的代码,可以通过传递不同的类型或常量值来生成不同的代码实例。这使 C++ 中的泛型编程变得更强大、更灵活且通用性良好。

在 C++11 中新增可变模板参数,支持模板接受任意数量的类型参数,可变模板参数的基本语法是在模板声明中使用省略号(...)来表示可以接受任意数量和类型的参数。

相关文章