美文网首页
C++模板及标准模板库

C++模板及标准模板库

作者: 帅碧 | 来源:发表于2016-11-16 10:16 被阅读0次

    模板

    • 模板是C++语言相对较新的一个重要特性。
      模板使程序员能够快速建立具有类型安全的类库集合和函数集合,它的实现,方便了大规模的软件开发。
    • 本节介绍了模板的概念、定义和使用模板的方法,通过这些介绍,使渎者有效地把握模板,以便能正确使用C++系统中日渐庞大的标准模板类库

    函数模板的一般定义形式:

    template<类型形式参数表> 
    返回类型 FunctionName(形式参数表)
    {
        //函数定义体
    }
    
    
    #include<iostream>
    using namespace std;
    template<class X>
    X Max(X a,X b)
    {
        return (a>b?a:b);
    }
    int main()
    {   
        int x1=20;
        int x2=30;
        cout<<"Max int = "<<Max<int>(x1,x2)<<endl;
        double y1=22.5;
        double y2=12.5;
        cout<<"Max double = "<<Max<double>(y1,y2)<<endl;
        char z1='A';
        char z2='B';
        cout<<"Max char = "<<Max<char>(z1,z2)<<endl;
    }
    //结果为:
    //Max int = 30
    //Max double = 22.5
    //Max char = B
    
    
    • 交换任一类类对象
    void swap(T& a,T& b)
      {
               T temp=a;
               a = b;
               b = temp;
    } 
    //有了函数模板之后,重载就不必要了
    
    

    类模板

    类模板的作用

    1. 使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值,能取任意类型(包括基本类型的和用户自定义类型)。
    2. 类模板定义:
    template <模板参数表>
    class 类名
    {类成员声明}
    
    
    1. 在类模板以外定义其成员函数:
    template <模板参数表>
    类型名 类名<T>::函数名 ( 参数表 )
    
    
    #include<iostream>
    using namespace std;
    template<class X,class Y>
    class Test
    {
        X m_t1;
        Y m_t2;
        public:
            Test(X t1,Y t2)
            {
                m_t1=t1;
                m_t2=t2;
            }
            void show()
            {
                cout<<"T1 = "<<m_t1<<"T2 = "<<m_t2<<endl;
            }
    };
    int main(int argc,char **argv)
    {
        Test<int,char>t(10,'S');
        t.show();
    }
    //结果为:
    //T1 = 10 T2 = S
    
    
    #include<iostream>
    using namespace std;
    template<class X,class Y>
    class Test
    {
        X m_t1;
        Y m_t2;
        public:
            Test(X t1,Y t2)
            {
                m_t1=t1;
                m_t2=t2;
            }
            void show()
            {
                cout<<"T1 = "<<m_t1<<"T2 = "<<m_t2<<endl;
            }
            void print();
    };
    template<class X,class Y>
    void Test<X,Y>::print()
    {
        cout<<"t1 = "<<m_t1<<"t2 = "<<m_t2<<endl;
    }
    int main(int argc,char **argv)
    {
        Test<int,char>t(10,'S');
        t.show();
        t.print();
    }
    //结果为:
    //
    

    类模板与模板类的区别

    1. 类模板是模板的定义,不是一个实实在在的类,定义中用到通用类型参数。
    2. 模板类是实实在在的类定义,是类模板的实例化。类定义中参数被实际类型所代替。

    模板的实现

    • 模板的定义很特殊,由 template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义

    标准模板类

    1. 将程序写得尽可能通用
    2. 将算法从特定的数据结构中抽象出来,成为通用的
    3. C++的模板为泛型程序设计奠定了关键的基础
    4. STL是泛型程序设计的一个范例
    • 容器
    • 迭代器
    • 算法
    • 函数对象

    七种基本容器

    1. 向量
    2. 双端队列
    3. 列表
    4. 集合
    5. 多重集合
    6. 映射
    7. 多重映射

    容器的接口

    1. 通用容器运算符
    • ==,!=,>,>=,<,<=,=
    1. 方法(函数)
    • 迭代方法
      begin(),end(),rbegin(),rend()
    • 访问方法
      size(),max_size(),swap(),empty()

    顺序容器的接口

    1. 插入方法
    • push_front(),push_back(),insert(),运算符“=”
    1. 删除方法
    • pop() ,erase(),clear()
    1. 迭代访问方法
    • 使用迭代器
    1. 其他顺序容器访问方法(不修改访问方法)
    • front(),back(),下标[ ]运算符
    1. 向量(vector)属于顺序容器,用于容纳不定长线性序列(即线性群体),提供对序列的快速随机访问(也称直接访问)
    2. 向量是动态结构,它的大小不固定,可以在程序运行时增加或减少。

    初始化vector容器方法

    1. vector<elementType> v; // 创建一个没有任何元素的空容器
    2. vector<elementType> v(otherVec); //调用拷贝构造函数创建新容器
    3. vector<elementType> v(size); //创建一个大小为size的对象v,并使用默认构造函数初始化该向量
    4. vector<elementType> v(n,elem); //创建一个大小为n的容器,并使用元素elem初始化每一个元素
      5.vector<elementType> v(begin,end); //创建容器v,并使用(begin,end)之间的元素初始化容器

    元素的插入

    1. veclist.push_back(elem); //将elem的一个拷贝插入到veclist的末尾
    2. veclist.insert(position,elem); //将elem的一个拷贝插入到指定的position的位置上
    3. veclist.insert(position,n,elem); //将elem的n个拷贝插入到由position指定的位置上
    4. veclist.insert(position,beg,end); //将从迭代器 beg至end-1 之间的元素插入到veclist 的position位置上

    向量容器的使用

    #include <vector>#include <algorithm>
    using namespace std;
    vector<int> num;// STL中的vector容器int element;
    // 从标准输入设备读入整数, // 直到输入的是非整型数据为止
    while (cin >> element)
     num.push_back(element);
    
    //访问容器内的元素
      for(int i=0; i<num.size(); i++){
           cout<<num[i]<<endl;
       }
    
    #include<iostream>
    #include<vector>
    using namespace std;
    vector<int>v;
    int main()
    {
        for(int i=0;i<11;i++)
        {
            v.push_back(i);
        }
        for(int j=0;j<v.size();j++)
        {
            cout<<v[j]<<" ";
        }
        cout<<endl;
    }
    //结果为
    //0 1 2 3 4 5 6 7 8 9 10
    
    
    #include<iostream>
    #include<vector>
    using namespace std;
    vector<int>v;
    int main()
    {
    /*  for(int i=0;i<11;i++)
        {
            v.push_back(i);
        }*/
        int elem;
        while(cin>>elem)
        {
            v.push_back(elem);
        }
        for(int j=0;j<v.size();j++)
        {
            cout<<v[j]<<" ";
        }
        cout<<endl;
    }
    //手动输入数组的值,以英语字母结束,并且打印出来
    
    
    • 正向遍历数组
    #include<iostream>
    #include<vector>
    using namespace std;
    vector<int>v;
    int main()
    {
        int elem;
        while(cin>>elem)
        {
            v.push_back(elem);
        }
        for(int j=0;j<v.size();j++)
        {
            cout<<v[j]<<" ";
        }
        cout<<endl;
        for(vector<int>::iterator it=v.begin();it<v.end();it++)
        {
            cout<<*it<<"\t";
        }
        cout<<endl;
    }
    //结果为:
    //1 2 3 4 5 g
    //则打印:1 2 3 4 5
    //再次输出:1\t2\t3\t4\t5
    
    

    容器的反向遍历

    1. 反向遍历是使用迭代器 reverse_iterator
      vector<int>::reverse_iterator ri;
    1. rbegin, rend
    • 反向遍历时使用rbegin,rend 来定位
    1. 反向遍历迭代器的使用与普通的迭代器一样,可以使用++在位移迭代器,使用* 运算符来取元素
    • 反向遍历数组
    #include<iostream>
    #include<vector>
    using namespace std;
    vector<int>v;
    int main()
    {
        int elem;
        while(cin>>elem)
        {
            v.push_back(elem);
        }
        for(int j=0;j<v.size();j++)
        {
            cout<<v[j]<<" ";
        }
        cout<<endl;
        for(vector<int>::reverse_iterator it=v.rbegin();it<v.rend();it++)
        {
            cout<<*it<<"\t";
        }
        cout<<endl;
    }
    //结果为:
    //手动输入:1 2 3 4 5g
    //则输出1 2 3 4 5
    //并且5 4 3 2 1
    
    
    1. 迭代器是面向对象版本的指针
    • 指针可以指向内存中的一个地址
    • 迭代器可以指向容器中的一个位置
    1. STL的每一个容器类模版中,都定义了一组对应的迭代器类。
    2. 使用迭代器,算法函数可以访问容器中指定位置的元素,而无需关心元素的具体类型。
    #include<iostream>
    using namespace std;
    #include<vector>
    void show(vector<int> vi)
    {
        vector<int>::iterator it;
        it=vi.begin();
        while(it!=vi.end())
        {
            cout<<*it++<<' ';
        }
        cout<<endl;
    };
    int main()
    {
        vector<int> vi(3,90);
        show(vi);
        int a[5]={3,4,5,6,7};
        vi.insert(vi.begin(),a,a+5);
        show(vi);
        vi.push_back(100);
        show(vi);
        cout<<"size:"<<vi.size()<<endl;
        vi.assign(5,99);
        show(vi);
        cout<<"size:"<<vi.size()<<endl;
    }
    //结果为:
    //90 90 90 
    //3 4 5 6 7 90 90 90 
    //3 4 5 6 7 90 90 90 100 
    //size:9
    //99 99 99 99 99 
    //size:5
    
    
    1. vector<int>::iterator iter;
    • 这条语句定义了一个名为iter的变量,它的数据类型是由vector<int>定义的iterator类型。
    1. begin和end操作
    • 如果容器中有元素的话,由begin返回的迭代器指向第一个元素:vector<int>::iterator iter = ivec.begin();
    • 由end操作返回的迭代器指向vector的“末端元素的下一个”。通常称为超出末端迭代器(off-the-end iterator) 。

    const_iterator

    1. 该类型只能访问容器内元素,但不能改变其值
    for (vector<string>::const_iterator iter = text.begin( ); 
    iter != text.end( ); ++iter) cout << *iter << endl; 
    
    
    1. 对const_iterator类型解引用时,则可以得到一个指向const对象的引用,如同任何常量一样,该对象不能进行重写。
    2. 不要把const_iterator对象与const的iterator对象混淆起来, const的iterator 不能做自增减, 但可以对它指向的元素赋值

    元素的删除

    1. veclist.clear(); //清空容器中所有元素
    2. veclist.erase(position); //删除position指定位置的元素
    3. veclist.erase(beg,end); //删除从beg至end-1之间的元素
    4. veclist.pop_back(); //删除最后一个元素

    list的初始化方法

    list的使用方法

    元素插入

    1. L.push_back(elem); //向容器的末尾插入元素elem的拷贝
    2. L.push_front(elem); //向容器的开端插入元素elem的拷贝
    3. L.insert(position, elem); //向容器的position位置插入元素elem的拷贝
    4. L.insert(position, n, elem); //向容器的position位置上插入元素elem的n个拷贝
    5. L.insert(position, beg, end); //将迭代器beg至 end-1 指向的内容插入到容器的position位置上
    6. L.splice(position, list); //将链表容器list中的元素插入到position位置上,并且清空list容器
    7. L.splice(position, list, pos); //将容器list中的pos位置上的元素插入到position位置上,并将pos位置上的元素从list中移除
    8. L.splice(position, list, beg, end); //将容器list中beg 至 end-1 位置上的元素插入到position位置上,并将这些元素从list中移除

    元素的删除

    1. L.pop_back(); //删除容器的最后一个元素
    2. L.pop_front(); //删除容器的第一个元素
      L.clear(); //删除容器的所有元素

    L.erase(position); //删除容器指定位置的元素
    L.erase(beg, end); //删除迭代器beg 至 end-1 之间的元素
    L.remove(elem); //移除与元素elem相等的元素

    #include<iostream>
    using namespace std;
    #include<list>
    int main()
    {
        int cpp[5]={3,6,1,7,5};
        int java[8]={6,4,7,8,15,2,3,9};
        int Unix[4]={5,2,6,9};
        list<int>li;
        li.insert(li.begin(),cpp,cpp+5);
        li.insert(li.begin(),java,java+8);
        li.insert(li.begin(),Unix,Unix+4);
        li.sort();
        li.unique();
        li.reverse();
        list<int>::iterator it=li.begin();
        while(it!=li.end())
        {
            cout<<*it++<<' ';
        }
        cout<<endl;
    }
    //结果为:
    //15 9 8 7 6 5 4 3 2 1 
    
    
    #include<iostream>
    using namespace std;
    #include<list>
    int main()
    {
        list<int>l1;
        int a[5]={3,4,5,6,7};
        list<int>l2(a,a+5);
        cout<<"l1.size():"<<l1.size()<<endl;
        cout<<"l2.size():"<<l2.size()<<endl;
        list<int>::iterator it;
        for(it=l2.begin();it!=l2.end();it++)
        {
            cout<<*it<<' ';
        }
        cout<<endl;
        //3,4,5,6,7
        it=l2.begin();
        it++;
        l2.erase(it);
        l2.insert(l2.begin(),100);
        l2.insert(l2.end(),200);
        //100,3,5,6,7,200
        for(it=l2.begin();it!=l2.end();it++)
        {
            cout<<*it<<' ';
        }
        cout<<endl;
    }
    //结果为:
    //l1.size():0
    //l2.size():5
    //3 4 5 6 7 
    //100 3 5 6 7 200 
    
    
    #include<iostream>
    using namespace std;
    #include<map>
    #include<string>
    int main()
    {
        //key(是唯一的)value
        map<int,string>mis;
        //(1)插入map元素
        mis.insert(make_pair(62,"东方不败"));
        mis.insert(make_pair(32,"岳不群"));
        mis.insert(make_pair(36,"林平之"));
        //(2)插入方式 这里的20不是下标!!!!!!
        mis[20]="劳德罗";
        map<int,string>::iterator it;
        it=mis.begin();
        //元素的位置和key相关和插入顺序没有关系
        //1.自动排序
        while(it!=mis.end())
        {
            cout<<it->first<<":"<<it->second<<endl;
            ++it;
        }
    }
    //结果为:
    //20:劳德罗
    //32:岳不群
    //36:林平之
    //62:东方不败
    
    
    #include<iostream>
    using namespace std;
    #include<map>
    #include<string>
    int main()
    {
        //key(是唯一的)value
        map<int,string>mis;
        //(1)插入map元素
        mis.insert(make_pair(62,"东方不败"));
        mis.insert(make_pair(32,"岳不群"));
        mis.insert(make_pair(36,"林平之"));
        //(2)插入方式 这里的20不是下标!!!!!!
        mis[20]="劳德罗";
        mis[36]="yyyy";
        map<int,string>::iterator it;
        it=mis.begin();
        //元素的位置和key相关和插入顺序没有关系
        //1.自动排序
        while(it!=mis.end())
        {
            cout<<it->first<<":"<<it->second<<endl;
            ++it;
        }
    }
    //结果为:
    //20:劳德罗
    //32:岳不群
    //36:yyyy
    //62:东方不败
    
    
    • 当出现两个下标相同时,用最后的一次

    练习

    补充

    #include<iostream>
    using namespace std;
    class Test
    {
        int m_t;
        public:
            Test()
            {
                
            }
            void lianxi()const
            {
                cout<<"lianxi const"<<endl;
            }
            void lianxi()
            {
                cout<<"lianxi"<<endl;
            }
    };
    int main()
    {
        const Test t;
        t.lianxi();
        Test t1;
        t1.lianxi();
    }
    
    

    相关文章

      网友评论

          本文标题:C++模板及标准模板库

          本文链接:https://www.haomeiwen.com/subject/pmtrpttx.html