【C++基础—— 泛型和模板】

C++ 泛型和模板

C++ 中的泛型编程技术包括模板和 STL(标准模板库),它们可以实现代码的通用性和重用性。本文将主要介绍 C++ 中的模板,以及如何使用它们来实现泛型编程。

模板基础

模板是一种将类型作为参数的编程技术。通过使用模板,可以编写通用的函数和类,从而使得编写的代码可以适用于多种数据类型。

函数模板

函数模板是一种通用的函数定义,其中一个或多个参数使用泛型类型。在调用函数模板时,需要指定实际类型。

示例代码:

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

int main() {
    
    
    int result1 = max(3, 5);        // result1 = 5
    double result2 = max(3.14, 2.71);   // result2 = 3.14
}

上述代码定义了一个函数模板 max,它接受两个类型相同的参数,并返回它们中的最大值。使用关键字 templatetypename 声明模板类型参数 T,在函数体中使用模板类型参数 T 代表任意类型。

类模板

类模板是定义通用类的一种方式,其中一个或多个成员使用泛型类型。与函数模板类似,在使用类模板时需要指定实际类型。

示例代码:

template <typename T>
class Stack {
    
    
public:
    void push(T val);
    T pop();
private:
    T data[100];
    int top;
};

template <typename T>
void Stack<T>::push(T val) {
    
    
    if (top < 100) {
    
    
        data[top++] = val;
    }
}

template <typename T>
T Stack<T>::pop() {
    
    
    if (top > 0) {
    
    
        return data[--top];
    } else {
    
    
        return T();
    }
}

int main() {
    
    
    Stack<int> int_stack;
    int_stack.push(1);
    int_stack.push(2);
    int result1 = int_stack.pop();     // result1 = 2
    int result2 = int_stack.pop();     // result2 = 1

    Stack<std::string> str_stack;
    str_stack.push("Hello");
    str_stack.push("World");
    std::string result3 = str_stack.pop();  // result3 = "World"
    std::string result4 = str_stack.pop();  // result4 = "Hello"
}

上述代码定义了一个类模板 Stack,它是一个栈数据结构,可以存储任意类型的数据。在类模板中声明成员函数时,需要在函数名前加上 template <typename T> 和类名 Stack<T> 表示成员函数属于类模板。

模板参数

模板参数可以是类型参数和非类型参数。类型参数包括类、结构体、指针、引用、枚举和模板类型参数;非类型参数包括整型常量、指向对象的指针和成员指针。

在使用模板时,可以将任何类型作为模板参数。如果模板参数是类或结构体,则需要提供相应的定义,以便编译器可以实例化该模板。

示例代码:

template <typename T, int size>
class Array {
    
    
public:
    void set(int index, T val) {
    
    
        if (index >= 0 && index < size) {
    
    
            data[index] = val;
        }
    }
    T get(int index) {
    
    
        if (index >= 0 && index < size) {
    
    
            return data[index];
        } else {
    
    
            return T();
        }
    }
private:
    T data[size];
};

struct Point3D {
    
    
    float x, y, z;
};

int main() {
    
    
    Array<int, 10> int_arr;
    int_arr.set(0, 1);
    int_arr.set(1, 2);
    int result1 = int_arr.get(0);   // result1 = 1

    Array<Point3D, 5> point_arr;
    point_arr.set(0, {
    
    1.0f, 2.0f, 3.0f});
    Point3D result2 = point_arr.get(0);  // result2.x = 1.0f, result2.y = 2.0f, result2.z = 3.0f
}

上述代码定义了一个模板类 Array,它包含一个大小为 size 的数据数组。在使用模板时,需要指定数据类型 T 和数组大小 size。在这里,Array<int, 10> 表示一个包含 10 个整数的数组,而 Array<Point3D, 5> 表示一个包含 5 个 Point3D 结构体的数组。

模板实现

在使用模板时,需要将模板的定义和实现分别放在 .h.cpp 文件中。由于编译器在编译时需要实例化模板,因此模板的定义和实现都需要在一个文件中。

例如,对于上述定义的类模板 Stack,可以将其定义放在 stack.h 文件中:

template <typename T>
class Stack {
    
    
public:
    void push(T val);
    T pop();
private:
    T data[100];
    int top;
};

将其实现放在 stack.cpp 文件中:

#include "stack.h"

template <typename T>
void Stack<T>::push(T val) {
    
    
    if (top < 100) {
    
    
        data[top++] = val;
    }
}

template <typename T>
T Stack<T>::pop() {
    
    
    if (top > 0) {
    
    
        return data[--top];
    } else {
    
    
        return T();
    }
}

在使用 Stack 类时,需要在文件头部包含 stack.h 文件,并在程序中实例化模板:

#include "stack.h"

int main() {
    
    
    Stack<int> int_stack;
    int_stack.push(1);
    int_stack.push(2);
    int result1 = int_stack.pop();     // result1 = 2
    int result2 = int_stack.pop();     // result2 = 1

    Stack<std::string> str_stack;
    str_stack.push("Hello");
    str_stack.push("World");
    std::string result3 = str_stack.pop();  // result3 = "World"
    std::string result4 = str_stack.pop();  // result4 = "Hello"
}

需要注意的是,模板的所有代码都需要放在头文件中,以便编译器在使用模板时可以实例化该模板。因此,通常情况下,模板不会将定义和实现分开放在不同的文件中。

猜你喜欢

转载自blog.csdn.net/muzillll/article/details/131098821