• C++
  • C++ 结构体模板学习笔记教程

  • @ 2025-8-10 15:02:29

C++ 结构体模板学习笔记教程

1. 结构体模板的基本概念

结构体模板(struct template)是C++中一种参数化的结构体定义方式,它允许我们创建一个通用的结构体框架,而不指定某些数据类型,直到使用时再确定具体类型。这种特性极大地提高了代码的复用性和灵活性,特别适合处理那些逻辑相同但数据类型不同的场景。

例如,我们可能需要一个存储两个相同类型数据的结构体(如坐标、范围等),对于intfloatdouble等不同类型,逻辑完全一致,此时使用结构体模板就能避免重复编写代码。

2. 结构体模板的定义与基本语法

定义格式

结构体模板的基本定义语法如下:

template <typename T1, typename T2, ...>  // 模板参数列表,可包含多个类型参数
struct 结构体模板名 {
    // 成员变量,可使用模板参数作为类型
    T1 成员1;
    T2 成员2;
    // ...
    
    // 成员函数,可使用模板参数作为参数类型或返回值类型
    返回值类型 函数名(T1 参数1, T2 参数2) {
        // 函数体
    }
};
  • template:关键字,声明后面是一个模板。
  • <typename T1, ...>:模板参数列表,typename 可替换为 class(二者在模板参数中含义相同),T1 等是类型参数的占位符(通常用大写字母表示)。

示例:简单的结构体模板

#include <iostream>

// 定义结构体模板:存储两个同类型数据
template <typename T>
struct Pair {
    T first;  // 第一个元素
    T second; // 第二个元素
    
    // 成员函数:输出两个元素
    void print() {
        std::cout << "(" << first << ", " << second << ")" << std::endl;
    }
};

int main() {
    // 使用模板创建具体类型的结构体变量(实例化)
    Pair<int> intPair = {10, 20};         // 存储int类型
    Pair<double> doublePair = {3.14, 5.67}; // 存储double类型
    Pair<std::string> strPair = {"Hello", "World"}; // 存储string类型
    
    intPair.print();
    doublePair.print();
    strPair.print();
    
    return 0;
}

输出结果:

(10, 20)
(3.14, 5.67)
(Hello, World)

3. 结构体模板的实例化

结构体模板本身并不是一个具体的类型,而是一个“模板”,需要实例化后才能使用。实例化就是指定模板参数的具体类型,生成一个具体的结构体类型。

显式实例化

在使用时通过 <具体类型> 明确指定模板参数,如:

// 实例化存储int类型的Pair结构体
Pair<int> intPair;
// 实例化存储std::string类型的Pair结构体
Pair<std::string> strPair;

隐式实例化(C++17及以上)

在某些情况下,编译器可以根据初始化数据自动推断模板参数类型(无需显式指定):

#include <iostream>

template <typename T>
struct Pair {
    T first;
    T second;
};

int main() {
    // C++17及以上支持:根据初始化值推断T为int
    Pair intPair = {10, 20}; 
    // 等价于 Pair<int> intPair = {10, 20};
    std::cout << intPair.first << ", " << intPair.second << std::endl;
    
    return 0;
}

4. 结构体模板的成员函数

结构体模板的成员函数可以在结构体内部定义(如前面的示例),也可以在结构体外部定义。外部定义时需要遵循特定的语法。

外部定义成员函数

#include <iostream>

template <typename T>
struct Box {
    T value;
    
    // 内部声明成员函数
    void setValue(T v);
    T getValue() const;
};

// 外部定义成员函数:需重复模板参数列表
template <typename T>
void Box<T>::setValue(T v) {
    value = v;
}

template <typename T>
T Box<T>::getValue() const {
    return value;
}

int main() {
    Box<float> floatBox;
    floatBox.setValue(3.14f);
    std::cout << floatBox.getValue() << std::endl; // 输出:3.14
    
    return 0;
}

5. 多参数结构体模板

结构体模板可以包含多个类型参数,适用于成员变量类型不同的场景。

示例:多参数模板

#include <iostream>
#include <string>

// 定义包含两个不同类型参数的模板
template <typename Key, typename Value>
struct KeyValue {
    Key key;    // 键(类型为Key)
    Value val;  // 值(类型为Value)
    
    // 打印键值对
    void display() {
        std::cout << key << " : " << val << std::endl;
    }
};

int main() {
    // 实例化:键为int,值为std::string
    KeyValue<int, std::string> kv1 = {1, "One"};
    // 实例化:键为std::string,值为double
    KeyValue<std::string, double> kv2 = {"PI", 3.14159};
    
    kv1.display(); // 输出:1 : One
    kv2.display(); // 输出:PI : 3.14159
    
    return 0;
}

6. 带默认参数的结构体模板

结构体模板的参数可以指定默认类型,当实例化时未指定该参数,就使用默认类型。

示例:默认参数模板

#include <iostream>

// 带默认参数的模板:T2默认是int
template <typename T1, typename T2 = int>
struct MixedPair {
    T1 a;
    T2 b;
    
    void print() {
        std::cout << "a: " << a << ", b: " << b << std::endl;
    }
};

int main() {
    // 只指定T1,T2使用默认int
    MixedPair<double> mp1 = {2.718, 100};
    // 同时指定T1和T2
    MixedPair<std::string, bool> mp2 = {"Flag", true};
    
    mp1.print(); // 输出:a: 2.718, b: 100
    mp2.print(); // 输出:a: Flag, b: 1
    
    return 0;
}

7. 结构体模板的嵌套

结构体模板可以嵌套在其他结构体(或结构体模板)中,形成更复杂的通用数据结构。

示例:嵌套结构体模板

#include <iostream>

// 内部结构体模板
template <typename T>
struct Node {
    T data;
    Node* next; // 指向同类型Node的指针
};

// 外部结构体模板:链表
template <typename T>
struct LinkedList {
    Node<T>* head; // 嵌套使用Node<T>
    
    // 构造函数:初始化空链表
    LinkedList() : head(nullptr) {}
    
    // 添加元素到链表头部
    void add(T value) {
        Node<T>* newNode = new Node<T>;
        newNode->data = value;
        newNode->next = head;
        head = newNode;
    }
    
    // 打印链表
    void print() {
        Node<T>* current = head;
        while (current != nullptr) {
            std::cout << current->data << " -> ";
            current = current->next;
        }
        std::cout << "nullptr" << std::endl;
    }
};

int main() {
    LinkedList<int> intList;
    intList.add(3);
    intList.add(2);
    intList.add(1);
    intList.print(); // 输出:1 -> 2 -> 3 -> nullptr
    
    return 0;
}

8. 结构体模板与函数的配合

结构体模板可以作为函数的参数、返回值,或在函数模板中使用。

示例:结构体模板作为函数参数

#include <iostream>

template <typename T>
struct Point {
    T x;
    T y;
};

// 函数模板:计算两点之间的距离(简化版,不考虑平方根)
template <typename T>
T distance(Point<T> p1, Point<T> p2) {
    T dx = p1.x - p2.x;
    T dy = p1.y - p2.y;
    return dx * dx + dy * dy; // 返回距离的平方
}

int main() {
    Point<int> p1 = {1, 2};
    Point<int> p2 = {4, 6};
    std::cout << "距离平方:" << distance(p1, p2) << std::endl; // 输出:25(3²+4²)
    
    return 0;
}

9. 结构体模板的实际应用场景

结构体模板在实际开发中应用广泛,以下是几个典型场景:

  • 通用数据容器:如存储键值对的KeyValue、存储范围的Range<T>等。
  • 数学运算:如表示坐标的Point<T>、向量Vector<T>等,支持不同精度的数值类型。
  • 数据转换:如实现不同类型数据的映射、包装等。

综合示例:通用范围检查器

#include <iostream>
#include <string>

// 通用范围结构体:检查值是否在[min, max]范围内
template <typename T>
struct Range {
    T min;
    T max;
    
    // 构造函数
    Range(T m, T M) : min(m), max(M) {}
    
    // 检查值是否在范围内
    bool contains(T value) const {
        return value >= min && value <= max;
    }
    
    // 打印范围信息
    void printRange() const {
        std::cout << "范围: [" << min << ", " << max << "]" << std::endl;
    }
};

int main() {
    // 整数范围
    Range<int> intRange(0, 100);
    intRange.printRange();
    std::cout << "50是否在范围内?" << (intRange.contains(50) ? "是" : "否") << std::endl;
    std::cout << "101是否在范围内?" << (intRange.contains(101) ? "是" : "否") << std::endl;
    
    // 浮点数范围
    Range<double> doubleRange(0.0, 1.0);
    doubleRange.printRange();
    std::cout << "0.5是否在范围内?" << (doubleRange.contains(0.5) ? "是" : "否") << std::endl;
    
    // 字符串范围(按字典序)
    Range<std::string> strRange("Apple", "Banana");
    strRange.printRange();
    std::cout << "Apricot是否在范围内?" << (strRange.contains("Apricot") ? "是" : "否") << std::endl;
    
    return 0;
}

输出结果:

范围: [0, 100]
50是否在范围内?是
101是否在范围内?否
范围: [0, 1]
0.5是否在范围内?是
范围: [Apple, Banana]
Apricot是否在范围内?是

总结

结构体模板是C++中实现代码复用和泛型编程的重要工具,通过本教程你应掌握:

  • 结构体模板的定义与基本语法(template <typename T>)。
  • 模板的实例化(显式指定类型或隐式推断)。
  • 成员函数的内部与外部定义方式。
  • 多参数模板和带默认参数的模板使用。
  • 结构体模板的嵌套及与函数的配合。

结构体模板的核心价值在于“一次定义,多次使用”,它能让相同的逻辑适配不同的数据类型,大幅减少重复代码。在实际开发中,合理使用结构体模板可以提高代码的灵活性和可维护性。

0 条评论

目前还没有评论...