目录介绍

  • 18.1 函数模版
    • 18.1.1 函数模版概念
    • 18.1.2 函数模板语法
    • 18.1.3 函数模板示例
    • 18.1.4 多类型参数函数模板
    • 18.1.5 显式指定模板参数
    • 18.1.6 函数模板的特化
    • 18.1.7 函数模板与重载
  • 18.2 类模版
    • 18.2.1 类模版概念
    • 18.2.2 类模板语法
    • 18.2.3 类模板示例
    • 18.2.4 多类型参数类模板
    • 18.2.5 类模板的特化
    • 18.2.6 类模板默认模板参数
    • 18.2.7 类模板嵌套
    • 18.2.9 类模板注意事项
  • 18.3 STL标准库模版
    • 18.3.1 STL核心组件
    • 18.3.2 容器(Containers)
    • 18.3.3 迭代器(Iterators)
    • 18.3.4 算法(Algorithms)
    • 18.3.5 函数对象(Function Objects)
  • 18.4 STL算法模版
    • 18.4.1 非修改序列算法
    • 18.4.2 修改序列算法
    • 18.4.3 排序算法
    • 18.4.4 查找算法
    • 18.4.5 数值算法
    • 18.4.6 总结一下
  • 18.5 STL迭代器
    • 18.5.1 迭代器的分类
    • 18.5.2 常用迭代器操作
    • 18.5.3 迭代器示例
    • 18.5.4 特殊迭代器
    • 18.5.5 迭代器适配器
  • 18.6 STL适配器
  • 18.7 STL函数对象

18.1 函数模版

在 C++ 中,函数模板是一种通用函数定义,允许你编写可以处理多种数据类型的函数。通过使用模板,你可以避免为每种数据类型编写重复的代码,从而提高代码的复用性和可维护性。

18.1.1 函数模版概念

模板就是建立通用的模具,大大提高复用性。

模板的特点:

  1. 模板不可以直接使用,它只是一个框架
  2. 模板的通用并不是万能的

C++另一种编程思想称为 ==泛型编程== ,主要利用的技术就是模板

  1. C++提供两种模板机制: 函数模板和类模板

18.1.2 函数模板语法

函数模板的定义使用 template 关键字,后跟模板参数列表。模板参数可以是类型参数(如 typename T)或非类型参数(如 int N)。

语法

template <typename T>
返回类型 函数名(参数列表) {
    // 函数体
}
  1. template --- 声明创建模板
  2. typename --- 表面其后面的符号是一种数据类型,可以用class代替
  3. T --- 通用的数据类型,名称可以替换,通常为大写字母

18.1.3 函数模板示例

示例 1:交换两个值

#include <iostream>

// 定义函数模板
template <typename T>
void swap(T &a, T &b) {
    T temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 10, y = 20;
    std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;
    swap(x, y); // 调用模板函数
    std::cout << "After swap: x = " << x << ", y = " << y << std::endl;

    double a = 1.5, b = 2.5;
    std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;
    swap(a, b); // 调用模板函数
    std::cout << "After swap: a = " << a << ", b = " << b << std::endl;

    return 0;
}

示例 2:返回最大值

#include <iostream>

// 定义函数模板
template <typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    int x = 10, y = 20;
    std::cout << "Max of " << x << " and " << y << " is " << max(x, y) << std::endl;

    double a = 1.5, b = 2.5;
    std::cout << "Max of " << a << " and " << b << " is " << max(a, b) << std::endl;

    return 0;
}

总结:

  • 函数模板利用关键字 template
  • 使用函数模板有两种方式:自动类型推导、显示指定类型
  • 模板的目的是为了提高复用性,将类型参数化

18.1.4 多类型参数函数模板

函数模板可以接受多个类型参数。示例

#include <iostream>

// 定义函数模板
template <typename T1, typename T2>
void printPair(T1 a, T2 b) {
    std::cout << "Pair: (" << a << ", " << b << ")" << std::endl;
}

int main() {
    printPair(10, 20.5); // 输出: Pair: (10, 20.5)
    printPair("Hello", 42); // 输出: Pair: (Hello, 42)
    return 0;
}

18.1.5 显式指定模板参数

注意事项:

  1. 自动类型推导,必须推导出一致的数据类型T,才可以使用
  2. 模板必须要确定出T的数据类型,才可以使用
//利用模板提供通用的交换函数
template<class T>
void mySwap(T &a, T &b) {
    T temp = a;
    a = b;
    b = temp;
}

//1、自动类型推导,必须推导出一致的数据类型T,才可以使用
void test1() {
    int a = 10;
    int b = 20;
    char c = 'c';
    mySwap(a,b);    // 正确,可以推导出一致的T
    //mySwap(a,c);    // 错误,推导不出一致的T类型
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
}

template<class T>
void func() {
    cout << "func 调用" << endl;
}

void test2() {
    //func(); //错误,模板不能独立使用,必须确定出T的类型
    func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板
}

int main() {
    test1();
    test2();
    return 0;
}

总结: 使用模板时必须确定出通用数据类型T,并且能够推导出一致的类型

18.1.6 函数模板的特化

函数模板的特化是指为特定类型提供特殊的实现。

示例

#include <iostream>

// 通用模板
template <typename T>
void print(T value) {
    std::cout << "Generic: " << value << std::endl;
}

// 特化版本(针对 const char*)
template <>
void print<const char*>(const char* value) {
    std::cout << "Specialized: " << value << std::endl;
}

int main() {
    print(10); // 调用通用模板
    print("Hello"); // 调用特化版本
    return 0;
}

18.1.7 函数模板与重载

函数模板可以与普通函数重载。编译器会优先选择最匹配的函数。

示例

#include <iostream>

// 普通函数
void print(int value) {
    std::cout << "Overloaded: " << value << std::endl;
}

// 函数模板
template <typename T>
void print(T value) {
    std::cout << "Template: " << value << std::endl;
}

int main() {
    print(10); // 调用普通函数
    print(10.5); // 调用函数模板
    return 0;
}

18.2 类模版

18.2.1 类模版概念

在 C++ 中,类模板是一种通用类定义,允许你编写可以处理多种数据类型的类。通过使用类模板,你可以避免为每种数据类型编写重复的代码,从而提高代码的复用性和可维护性。

18.2.2 类模板语法

类模板的定义使用 template 关键字,后跟模板参数列表。模板参数可以是类型参数(如 typename T)或非类型参数(如 int N)。

语法

template <typename T>
class 类名 {
    // 类成员
};
  • typename T:表示一个类型参数,T 可以是任意类型(如 intdoublestd::string 等)。
  • 在类中,T 可以像普通类型一样使用。

18.2.3 类模板示例

示例 1:简单的类模板

#include <iostream>

// 定义类模板
template <typename T>
class Box {
private:
    T value;
public:
    Box(T v) : value(v) {}
    void print() {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    Box<int> intBox(10); // 实例化一个 Box<int> 对象
    intBox.print(); // 输出: Value: 10

    Box<double> doubleBox(3.14); // 实例化一个 Box<double> 对象
    doubleBox.print(); // 输出: Value: 3.14

    return 0;
}

示例 2:类模板的成员函数。类模板的成员函数可以在类外定义,但需要显式指定模板参数。

#include <iostream>

template <typename T>
class Box {
private:
    T value;
public:
    Box(T v);
    void print();
};

// 类外定义构造函数
template <typename T>
Box<T>::Box(T v) : value(v) {}

// 类外定义成员函数
template <typename T>
void Box<T>::print() {
    std::cout << "Value: " << value << std::endl;
}

int main() {
    Box<int> intBox(42);
    intBox.print(); // 输出: Value: 42

    Box<std::string> stringBox("Hello");
    stringBox.print(); // 输出: Value: Hello

    return 0;
}

18.2.4 多类型参数类模板

类模板可以接受多个类型参数。示例

#include <iostream>

template <typename T1, typename T2>
class Pair {
private:
    T1 first;
    T2 second;
public:
    Pair(T1 f, T2 s) : first(f), second(s) {}
    void print() {
        std::cout << "Pair: (" << first << ", " << second << ")" << std::endl;
    }
};

int main() {
    Pair<int, double> p1(10, 3.14);
    p1.print(); // 输出: Pair: (10, 3.14)

    Pair<std::string, int> p2("Hello", 42);
    p2.print(); // 输出: Pair: (Hello, 42)

    return 0;
}

18.2.5 类模板的特化

类模板的特化是指为特定类型提供特殊的实现。

示例

#include <iostream>

// 通用模板
template <typename T>
class Box {
private:
    T value;
public:
    Box(T v) : value(v) {}
    void print() {
        std::cout << "Generic: " << value << std::endl;
    }
};

// 特化版本(针对 const char*)
template <>
class Box<const char*> {
private:
    const char* value;
public:
    Box(const char* v) : value(v) {}
    void print() {
        std::cout << "Specialized: " << value << std::endl;
    }
};

int main() {
    Box<int> intBox(10);
    intBox.print(); // 输出: Generic: 10

    Box<const char*> stringBox("Hello");
    stringBox.print(); // 输出: Specialized: Hello

    return 0;
}

18.2.6 类模板默认模板参数

可以为类模板的模板参数指定默认值。示例

#include <iostream>

template <typename T = int>
class Box {
private:
    T value;
public:
    Box(T v) : value(v) {}
    void print() {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    Box<> intBox(10); // 使用默认模板参数 int
    intBox.print(); // 输出: Value: 10

    Box<double> doubleBox(3.14); // 显式指定模板参数 double
    doubleBox.print(); // 输出: Value: 3.14

    return 0;
}

18.2.7 类模板嵌套

类模板可以嵌套在其他类或类模板中。示例

#include <iostream>

template <typename T>
class Outer {
public:
    template <typename U>
    class Inner {
    private:
        U value;
    public:
        Inner(U v) : value(v) {}
        void print() {
            std::cout << "Inner value: " << value << std::endl;
        }
    };
};

int main() {
    Outer<int>::Inner<double> inner(3.14);
    inner.print(); // 输出: Inner value: 3.14

    return 0;
}

18.2.9 类模板注意事项

  1. 模板参数推断:类模板的模板参数不能自动推断,必须显式指定。
  2. 模板定义与声明:类模板的定义通常放在头文件中,因为编译器需要看到完整的定义才能实例化模板。
  3. 模板实例化:模板本身不是类,只有在使用时才会生成具体的类实例。

18.3 STL标准库模版

C++ 标准模板库(Standard Template Library,STL)是 C++ 标准库的一部分,提供了一系列通用的模板类和函数,用于实现常见的数据结构和算法。

18.3.1 STL核心组件

STL 的核心组件包括 容器迭代器算法函数对象

18.3.2 容器(Containers)

容器是用于存储数据的模板类,分为以下几类:

  • 序列容器:按线性顺序存储数据,如 vectorlistdeque
  • 关联容器:按键值对存储数据,如 setmapmultisetmultimap
  • 无序关联容器:基于哈希表实现,如 unordered_setunordered_map
  • 容器适配器:基于其他容器实现的特殊接口,如 stackqueuepriority_queue

18.3.3 迭代器(Iterators)

迭代器是用于遍历容器中元素的对象,类似于指针。STL 提供了多种迭代器:

  • 输入迭代器:只能读取元素。
  • 输出迭代器:只能写入元素。
  • 前向迭代器:可以读取和写入元素,支持单向遍历。
  • 双向迭代器:支持双向遍历。
  • 随机访问迭代器:支持随机访问。

18.3.4 算法(Algorithms)

STL 提供了大量通用算法,用于操作容器中的数据,如排序、查找、遍历等。这些算法通过迭代器与容器交互。

18.3.5 函数对象(Function Objects)

函数对象是重载了 operator() 的类对象,可以像函数一样调用。STL 中的许多算法支持函数对象作为参数。

18.4 STL算法模版

18.4.1 非修改序列算法

find 查找容器中指定值的第一个匹配项。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    auto it = std::find(vec.begin(), vec.end(), 3);
    if (it != vec.end()) {
        std::cout << "Found: " << *it << std::endl; // 输出: Found: 3
    }
    return 0;
}

count 统计容器中指定值的出现次数。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 2, 3, 2};
    int cnt = std::count(vec.begin(), vec.end(), 2);
    std::cout << "Count: " << cnt << std::endl; // 输出: Count: 3
    return 0;
}

for_each 对容器中的每个元素执行指定操作。

#include <iostream>
#include <vector>
#include <algorithm>

void print(int x) {
    std::cout << x << " ";
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::for_each(vec.begin(), vec.end(), print); // 输出: 1 2 3 4 5
    return 0;
}

18.4.2 修改序列算法

这些算法会修改容器中的元素。

2.1 copy

将一个容器的元素复制到另一个容器。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> src = {1, 2, 3, 4, 5};
    std::vector<int> dst(5);
    std::copy(src.begin(), src.end(), dst.begin());
    for (int i : dst) {
        std::cout << i << " "; // 输出: 1 2 3 4 5
    }
    return 0;
}

2.2 fill

将容器中的元素填充为指定值。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec(5);
    std::fill(vec.begin(), vec.end(), 10);
    for (int i : vec) {
        std::cout << i << " "; // 输出: 10 10 10 10 10
    }
    return 0;
}

2.3 transform

对容器中的每个元素进行转换,并将结果存储到另一个容器。

#include <iostream>
#include <vector>
#include <algorithm>

int square(int x) {
    return x * x;
}

int main() {
    std::vector<int> src = {1, 2, 3, 4, 5};
    std::vector<int> dst(src.size());
    std::transform(src.begin(), src.end(), dst.begin(), square);
    for (int i : dst) {
        std::cout << i << " "; // 输出: 1 4 9 16 25
    }
    return 0;
}

18.4.3 排序算法

3.1 sort

对容器中的元素进行排序。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {5, 3, 1, 4, 2};
    std::sort(vec.begin(), vec.end());
    for (int i : vec) {
        std::cout << i << " "; // 输出: 1 2 3 4 5
    }
    return 0;
}

3.2 stable_sort

稳定排序,保持相等元素的相对顺序。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {5, 3, 1, 4, 2};
    std::stable_sort(vec.begin(), vec.end());
    for (int i : vec) {
        std::cout << i << " "; // 输出: 1 2 3 4 5
    }
    return 0;
}

3.3 partial_sort

对容器中的部分元素进行排序。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {5, 3, 1, 4, 2};
    std::partial_sort(vec.begin(), vec.begin() + 3, vec.end());
    for (int i : vec) {
        std::cout << i << " "; // 输出: 1 2 3 5 4
    }
    return 0;
}

18.4.4 查找算法

4.1 binary_search

在有序容器中查找指定值。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    bool found = std::binary_search(vec.begin(), vec.end(), 3);
    std::cout << (found ? "Found" : "Not found") << std::endl; // 输出: Found
    return 0;
}

4.2 lower_bound

返回第一个不小于指定值的元素位置。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    auto it = std::lower_bound(vec.begin(), vec.end(), 3);
    std::cout << "Lower bound: " << *it << std::endl; // 输出: Lower bound: 3
    return 0;
}

4.3 upper_bound

返回第一个大于指定值的元素位置。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    auto it = std::upper_bound(vec.begin(), vec.end(), 3);
    std::cout << "Upper bound: " << *it << std::endl; // 输出: Upper bound: 4
    return 0;
}

18.4.5 数值算法

5.1 accumulate

计算容器中元素的和。

#include <iostream>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    int sum = std::accumulate(vec.begin(), vec.end(), 0);
    std::cout << "Sum: " << sum << std::endl; // 输出: Sum: 15
    return 0;
}

5.2 inner_product

计算两个容器的内积。

#include <iostream>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> vec1 = {1, 2, 3};
    std::vector<int> vec2 = {4, 5, 6};
    int result = std::inner_product(vec1.begin(), vec1.end(), vec2.begin(), 0);
    std::cout << "Inner product: " << result << std::endl; // 输出: Inner product: 32
    return 0;
}

18.4.6 总结一下

STL 算法提供了强大的功能,可以高效地操作容器中的数据。常用的算法包括:

  • 非修改序列算法:如 findcountfor_each
  • 修改序列算法:如 copyfilltransform
  • 排序算法:如 sortstable_sortpartial_sort
  • 查找算法:如 binary_searchlower_boundupper_bound
  • 数值算法:如 accumulateinner_product
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]