zoukankan      html  css  js  c++  java
  • C++ 实现 STL 标准库和算法(二)template 编程和迭代器粗解 实验楼笔记

    一、template 编程和迭代器粗解

    1.1 实验内容

    本节内容主要讲述 c++11 模板的用法,以后的代码中会大量的用到模板的知识。同时简单讲解迭代器的相关知识,为后面容器和算法的内容作铺垫。

    1.2 实验知识点

    • 模板编程
      • 基本语法
      • 模板函数
      • 类模板和成员模板
      • 模板类中的静态成员
      • typename和class
    • 迭代器
      • 迭代器详解
      • 迭代器种类和使用
     

    基本语法

    模板编程是 STL 的基石,也是 c++11 的核心特性之一。模板是相对于编译器而言,顾名思义就是向编译器提供一个处理事务的模板,以后需要处理的东西,如果都是这个事务类型,那么统统用这个模板处理。
    三、函数模板
    模板的基本语法如下:
    template <typename/class T>
    template 告诉编译器,接下来是一个模板 ,typename 和 class 都是关键字,在这里二者可以互用没有区别。在< > T 叫做模板形参,一旦模板被实例化,T 也会变成具体的类型。接下来,我们看一个例子。
     
    代码实例:
    template <typename T>
    T add(const T lva ,const T rva)
    {
     
    T a ;
     
    a = lva + rva ;
     
    return a;
    }
     
    这是一个模板函数的简单实例,所有模板函数在开始都需要 template 语句,以告诉编译器这是一个模板和参数等必要信息,当然里面的 T 可以取任意你喜欢的名字 ,模板参数个数也是任意更换的。 还要提醒的一点是:template <typename T1 ,typename T2 = int>函数模板是支持默认参数的,T1 、T2顺序在默认情况下是可以任意的,不用严格按照从右到左的顺序。
    然后就是使用了,我们可以写出add(1,2) 这样的函数,也可以写出add(2.5,4.6)这样的函数,向 add 函数提供参数时,编译器会自动分析参数的类型,然后将所有用到 T 定义的换成相对性的类型,以上的两个函数在编译期间会生成
    int add(const int lva ,const int rva)
    {
     
    int a ;
     
    a = lva + rva ;
     
    return a;
    }
    double add(const double lva ,const double rva)
    {
     
    double a ;
     
    a = lva + rva ;
     
    return a;
    }
    这样的两个具体函数。如果我们使用add(1,2.0)是会报错的,编译器无法找到add(int,double)。大家可以自己分析一下为什么。
     
    四、类模板和成员模板


     

    类模版

    c++11 不仅支持对函数的模板化,也支持对类的模板,下面来看基本的语法是怎样的:
    template <class T>
    class Myclass
    {
    T a;
    public:
    T add(const T lva ,const T rva);
    };
     
    template <class T>
    T Myclass<T>::add(const T lva, const T rva)
    {
    a = lva + rva;
    return a;
    }
    这是一个简单并且典型的类模板,在程序中给出模板并不能使用它,还必须实例化,比如:
    Myclass<int> A; //用 int 实例化一个类A
    Myclass<double> B; //用 double 实例化一个类B
    当程序编译到这里时就会按照我们给出的类型,声明两组类和两组类函数。注意,在这里我们一定要显式给出类型 T 。类模板不像是函数模板 ,函数模板会根据参数推断类型。 当然类模板也支持默认参数,但是类模板必须严格从右往左默认化。

    成员模板

    模板的使用范围是广泛的,不仅可以用作函数模板,类模板,还可以用作 class ,struct ,template class 的成员。而要实现 STL 这是我们必须掌握和使用的特性。我们先看一个简单的例子,用上面的类改编而来:
    template <class T>
    class Myclass
    {
    public:
    T a;
    template <typename type_1 , typename type_2>
    type_1 add(const type_1 lva ,const type_2 rva);
    };
     
    template <class T>
    template <typename type_1,typename type_2>
    type_1 Myclass<T>::add(const type_1 lva, const type_2 rva)
    {
    a = lva + rva;
    return a;
    }
     
    在类的声明中使用了一个嵌套的模板声明。且通过作用域运算符 :: 指出 add 是类的成员,需要注意的一点,有些编译器不支持模板成员,而有些编译器不支持在类外定义。我们默认大家的编译器都支持。模板如此强大,甚至允许我们在模板类中再建立模板类:
    template <class T>
    class Myclass
    {
    public:
    T a;
    template <typename type_1 , typename type_2>
    type_1 add(const type_1 lva ,const type_2 rva);
     
    template <class type_3>
    class Myclass_2; // 声明放在这里,具体定义放在类外进行。
    Myclass_2<T> C; // 定义一个Myclass_2 类 A。使用 T 进行实例化
    };
     
    template <class T>
    template <typename type_1,typename type_2>
    type_1 Myclass<T>::add(const type_1 lva, const type_2 rva)
    {
    a = lva + rva;
    return a;
    }
     
    template <class T>
    template <class type_3>
    class Myclass<T>::Myclass_2
    {
    public:
    type_3 value;
    type_3 sub(const type_3 a , const type_3 b) {vlaue = a - b;}
    };
     
    当然我们暂时还用不到这样复杂的东西,这里只是展现了模板的部分特性。
     
     
    五、模板类中的静态成员
     
     
     
    我们知道,在类中定义的静态成员是存储在静态区中,被所有类对象共享,并不属于某一个类所有,同样的在模板类中的静态成员也不会被复制多份,而是被同类实例化的类对象共享,比如所有 int 和所有 double 的类对象,享有相互独立的静态变量。也可以说是编译器生成了 int 和 double 两个版本的类定义
     
    六、typename 和 class
     
    typenameclass是模板中经常使用的两个关键词 ,在模板定义的时候没有什么区别。以前用的是 class,后来 c++ 委员会加入了 typename。因为历史原因,两个是可以通用的。对有些程序员来说,在定义类模板的时候,常常使用 class 作为关键字,增加代码可读性。其它则用 typename,上面的代码大都遵循这样的标准,但是并无强制规定。但是如果二者没有差别,为什么还要加入typename呢?c++标准委员会不会增加无用的特性,让我们来看一个例子:
    class Myclass{
    public:
    Myclass();
    typedef int test; //定义类型别名
    }
    template <class T>
    class Myclass2{
    public:
    Myclass2();
    T::test *a // 声明一个指向T::test类型的指针。
    // typename T::test * a
    }
    以上的代码没有全部写完,大家觉得编译器能够过吗?答案是不能,因为在 c++ 中,允许我们在类中定义一个类型别名,且使用的时候和类名访问类成员的方法一样。这样编译器在编译的时候就会产生二义性,它根本不知道这是一个类型还是别名,所以我们加上 typename 显式说明出来。当然如果这里没有二义性,比如Myclass ::test * a ,加上 typename 是会报错的。此外,在 class 的 STL 底层还有一个特性,用于保留模板参数,但是在 c++17 中已经舍弃,所以我们没有讲。
     
     
    七、实验总结
     
     
    模板是 c++ 最重要的特性之一,模板函数、模板类、类中的模板函数、类中的模板类、模板类中的模板类等等,可以写出太多强大的代码,这也是模板的魅力所在,而 STL 就是基于模板的,大家一定要掌握模板的基本用法。
    引用《c++ primer》, 《STL 源码解析》
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    入门菜鸟
    FZU 1202
    XMU 1246
    Codeforces 294E Shaass the Great 树形dp
    Codeforces 773D Perishable Roads 最短路 (看题解)
    Codeforces 814E An unavoidable detour for home dp
    Codeforces 567E President and Roads 最短路 + tarjan求桥
    Codeforces 567F Mausoleum dp
    Codeforces 908G New Year and Original Order 数位dp
    Codeforces 813D Two Melodies dp
  • 原文地址:https://www.cnblogs.com/hx97/p/11192953.html
Copyright © 2011-2022 走看看