zoukankan      html  css  js  c++  java
  • [知识点] 1.5.4 模板与 STL

    总目录 > 1 语言基础 > 1.5 C++ 进阶 > 1.5.4  模板与 STL

    前言

    模板是之前几乎没接触过的东西,在 C++ 中使用得其实也挺多的;STL 就不多说了,太好用了。

    子目录列表

    1、模板的概念

    2、函数模板

    3、类模板

    4、STL

    1.5.4  模板与 STL

    1、模板的概念

    模板(Template),是 C++ 实现代码重用机制的重要工具,是泛型技术(即与数据类型无关的通用程序设计技术)的基础。它把算法设计从具体数据类型中分离出来,能够设计出独立于数据类型的通用模板程序,分为函数模板类模板两类。

    有些时候,我们设计某些功能需要针对诸多不同的数据类型,但除此之外代码完全一致,为此不得不编写多个具体到不同数据类型的程序,比如一个简单的求最大值函数

    int max(int a, int b) {
        return a > b ? a : b;
    }
    
    double max(double a, double b) {
        return a > b ? a : b;
    }
    
    char max(char a, char b) {
        return a > b ? a : b;
    }

    1.1  C 语言基础 中的预处理器部分,我们提到的宏定义 #define 可以解决这个问题,即:

    #define max(a, b) (a < b ? a : b)

    但宏定义一直存在的最大问题就是会避开类型检查机制,并且因为可操作性太强,以至于非常容易出现难以意料的错误。而模板的出现,让一切变得简单而规范。

    模板就像工艺制造中的模具一样,功能已经被固定下来,而数据类型就像填充的材质一样,是可以选择的;最后生产出来的产品,便是函数或者类。以上述求最大值函数为例,其函数模板为:

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

    关键字 template 表示定义模板(这个代码编辑器竟然不识别 template),< >参数表typename 表示 T 可以为任何数据类型,称为类型参数,可以用 class 代替,两者完全等价。

    2、函数模板

    前面已经用函数模板举了个例子,其一般形式为:

    template <模板参数表>
    返回类型 函数名(参数表) {
        ...
    }

    注意,template 语句和函数模板的定义之间不能有任何其他语句

    当编译器遇到 template 和跟随其后的函数定义时,它只是简单地知道这个函数模板以后可能会用到,而并不会据此有任何操作。当编译器遇到对其的调用时,才会根据调用语句中实参的具体类型生成代码,这一过程叫做模板的实例化,生成的函数称作模板函数

    注意,使用函数模板时,编译器并不会进行任何参数类型的隐式转换,如果出现不匹配的情况,将会直接报错。诸如上述求最大值模板,如果调用 max(2, 3.2),系统会将 2 判定为 int 类型,而 3.2 为 double 类型,但模板并未允许两者为不同数据类型,故出现错误。解决这个问题,可以:

    ① 显式转换类型;

    ② 显式指定函数模板实例化的类型参数,比如:min<double>(2, 3.2);

    ③ 指定多个模板参数,比如:

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

    (当然这样写其实依旧不够准确,但确实不会导致编译错误,更好的办法是将返回类型替换成 C++ 11 标准中的 auto,关于 auto 请参见 施工中)

    模板参数还可以为确定的数据类型,称为非类型模板参数,和普通函数的形参定义方式和作用是类似的,举个例子:

    template <typename T, int n>
    void sort(T a[n]) {
        for (int i = 1; i < n; i++)
            for (int j = i + 1; j <= n; j++)
                if (a[i] > a[j])
                    swap(a[i], a[j]);
    } 
    
    int a[] = {1, 3, 4, 2, 9, 5, 8, 10, 6, 7};
    sort <int, 10> (a);

    注意,非类型参数只能被传递常数,而不能传递变量。

    3、类模板

    类模板与类的关系形如函数模板与函数的关系,其一般形式为:

    template <模板参数表>
    class 类名 {
        ...
    }; 

    关于类模板与模板类的关系,以及模板参数不再赘述,直接以一个自定义的栈类模板举例:

    template <typename T, int n>
    class Stack {
        T a[n];
        int top;
    public:
        Stack() {
            T = 0;
        }
        void push(T o);
        T pop() {
            if (top <= 0) {
                cout << "error" << endl;
                return 0;
            }
            top--;
            return a[top];
        }
        bool empty() {
            return top == 0;
        }
    };
    
    template <typename T, int n>
    void Stack <T, n> :: push(T o) {
        if (top == n) {
            cout << "error" << endl;
            return 0;
    } a[top
    ++] = o; } Stack <int, 10> s;

    其中,pop() 函数使用的是类内定义,无异于普通类;push() 函数使用的是类外定义,则在定义时需要再次声明模板,并且加上完整的类型限定符。

    由类模板实例化生成针对具体数据类型的模板类,再由模板类定义模板对象。

    4、STL

    ① STL 简介

    上面已经介绍了如何自定义模板,而 C++ 内置了一套非常完善的标准模板库,将诸多组件实现了标准化,极大便捷了开发者对程序的编写。

    标准模板库(Standard Template Library, STL),包含:容器(Container),迭代器(Iterator),算法(Algorithm),空间配置器(Allocator),配接器(Adapter),仿函数(Functor),前三者为核心内容。它们被保存在如下 13 个头文件:

    <algorithm>, <deque>, <functional>, <iterator>, <vector>, <list>, <map>, <memory.h>, <numeric>, <queue>, <set>, <stack>, <utility>

    ② STL 容器

    容器(Container)是用来存储其他对象的对象。容器是容器类的实例,容器类是用类模板实现的,适用于各种数据类型,包含:顺序容器(序列式容器)、关联容器和容器适配器。

    > 顺序容器

    顺序容器是将同类型对象的有限集按顺序组织在一起的容器,用来表示线性数据结构,包括:向量(Vector),列表(List)和双端队列(Deque)。

    还有一种特殊的顺序容器:值对(pair)

    > 关联容器

    关联容器是非线性容器,用来根据键(key)进行快速存储、检索数据的容器,可以存储值的集合或者键-值对(Key-Value),主要包括:集合(Set),多重集合(Multiset),映射(Map)和多重映射(Multimap)

    > 容器适配器

    容器适配器本质上并不是容器,因为它没有迭代器,但依旧归类于容器;它由栈(Stack),队列(Queue)和优先队列(Priority_queue)组成。

    ③ STL 迭代器

    迭代器(Iterator)是一个对象,常用来遍历容器,可以认为是基于模板的指针,可以指示容器中的元素位置,遍历各个元素。迭代器本身提供了适用于多种容器类型的通用操作,开发者无需知道实际类型。

    迭代器是 STL 的核心,用于定义哪些算法可以在容器中使用,是容器和算法之间的桥梁。如果某个容器需要使用迭代器,则需要定义它,一般形式为:

    容器类型 <容器参数表> :: iterator 迭代器名; 

    举个例子:

    list <int> l;
    list <int> :: iterator iter; 

    迭代器提供的主要操作如下:

    施工中

    ④ STL 算法

    算法(Algorithm)是用模板技术实现的适用于各个容器的通用程序,一般通过迭代器间接操作容器元素,并返回迭代器作为算法运算的结果。STL 共计提供了超过 100 个实现算法的模板函数,基本都包含在 <algorithm> 库中,其中许多算法不仅适用于容器类型,还适用于普通的 C++ 数组或者自定义容器。

  • 相关阅读:
    java的(PO,VO,TO,BO,DAO,POJO)解释
    java中的几种对象(PO,VO,DAO,BO,POJO)
    mybatis如何根据mapper接口生成其实现类
    MyBatis接口的简单实现原理
    Fast-settling synchronous-PWM-DAC filter has almost no ripple
    CMOS DACs act as digitally controlled voltage dividers
    Programmable current source requires no power supply
    Add margining capability to a dc/dc converter
    Use an LM317 as 0 to 3V adjustable regulator
    Simple microcontroller-temperature measurement uses only a diode and a capacitor
  • 原文地址:https://www.cnblogs.com/jinkun113/p/13726346.html
Copyright © 2011-2022 走看看