C++ 模板和泛型编程(掌握Vector等容器的使用)

1. 泛型

       泛型编程,一次编写就能泛化到各种数据类型,例如整数、浮点数、字符和布尔类型以及自己定义结构体、函数和类。

       泛型是在编译时,由编译器决定实际将泛型替换为具体的类型(属于静态多态)。

       C++通过模板的方式提供了泛型编程,包括 函数模板和类模板, 对应的实例就是模板函数和模板类。在对应的函数模板内,可以处理多种模板类型。

       在实际开发中,可以利用模板完成抽象和封装,例如实现一个自定义CustomContainer,内部为2维动态数组,数组内可以放置任意相同类型的数据结构。 (ps: Python等动态类型语言,似乎天生自带此操作。)

    template <class Type> class CustomContainer
    {
    public:
        using reference = Type&;
        using const_reference = const Type&;

    public:
        CustomContainer() : data_array(nullptr), second_ite(0), first_ite(0), max_second_ite(0), first_dim(100), second_dim(200) {}
        ~CustomContainer() { deinit(); }

        void init(int fir = 100, int sec = 200)
        {
            max_second_ite = 0;
            first_ite = 0;
            second_ite = 0;
            first_dim = fir;
            second_dim = sec;
            data_array = new Type* [second_dim] { nullptr };
            data_array[0] = new Type[first_dim];
        }

        void deinit()
        {
            int stop = max(second_ite, max_second_ite);
            if (data_array != nullptr)
            {
                for (int i = 0; i <= stop; ++i)
                {
                    if (data_array[i] != nullptr)
                    {
                        delete[] data_array[i];
                        data_array[i] = nullptr;
                    }
                }
                delete[] data_array;
                data_array = nullptr;
            }
            second_ite = 0;
            first_ite = 0;
            max_second_ite = 0;
        }

private:
        Type** data_array;
        int first_dim, second_dim;
        int first_ite, second_ite;
        int max_second_ite;
    };
}

 

 

 

       以函数模型为例:

#include <iostream>
using namespace std;
template
<class T> // 函数模板,typename或class关键字均可 T min(T a[], int n) { int i; T minv = a[0]; for (i = 1; i < n; i++) // n-1次 { // n为数组长 if (minv > a[i]) { minv = a[i]; } } return minv; } int main() { int a[] = {8, 10, 0, 1, 7, 4, 9, 6, 11}; double b[] = {1.2, -3.4, 6.9, 7.2, 8.9}; cout << "a数组的最小值为:" << min(a, 9) << endl; cout << "b数组的最小值为:" << min(b, 5) << endl; return 0; }

 

2. 容器

       容器就是提供能够填充任意类型的数据的数据结构。C++中的STL基于模板实现了常用的标准抽象数据结构,例如vector就很类似于python中的list,本质上是动态数组。

       Vector支持push、pop等操作(Vector内部基于new和delete分配和回收内存,内部是一块连续的内存,在capcity不够时进行扩容)。使用Vector可以自动回收内存,可以避免内存泄漏。通常可以用于接口传递Vector的引用,避免传递外部new的数据。

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector <int> v1;
    v1.push_back(1);
    v1.push_back(2);

    //迭代器 
    v1.insert(v1.begin(), 0);//头部插入
    v1.insert(v1.end(), 4);  //尾部插入 
    v1.insert(v1.end()-1, 3);//倒数第二位置     
    v1[4] = 10;  //v1[5] = 6;越界错误
    for (int i=0; i<v1.size(); i++) {
        cout << v1[i] << ' ';
    } 
    cout << endl;

    v1.pop_back();   //删除尾部 10 
    v1.erase(v1.begin()); //删除头 0 
    v1.erase(v1.begin(), v1.end()); //全删
    cout << "全删后:";  // v1.clear();
    for (int i=0; i<v1.size(); i++) {
        cout << v1[i] << ' ';
    }  
      
    vector <string> v;
    v.push_back("food");
    v.push_back("candy");
    v.push_back("apple");
    sort(v.begin(), v.end());
    vector <string>::iterator it; //迭代器 
    for (it=v.begin(); it!=v.end(); it++) {
        cout << *it << " ";    
    }
    cout << endl;    

    return 0;
}

 

#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
 
int main()
{
    vector<int> obj;               //创建一个向量存储容器 int(定义了一系列操作的动态数组
    
    for (int i=0; i<20; i++)       // push_back(elem)在数组最后添加数据 
    {
        obj.push_back(i);
        cout << obj[i] << ",";    
    }
    
    cout << "\nmax_size:" << obj.max_size() << ","; 
    cout << "\ncapacity:" << obj.capacity() << ",";  
    cout << "\nsize:" << obj.size() << ",";  
    cout << "\nempty:" << obj.empty() << ",";  
    
    for (int i=0; i<5; i++)         //去掉数组最后一个数据 
    {
        obj.pop_back();
    }
       obj.push_back(10);
    obj.push_back(30);
    
    reverse(obj.begin(), obj.end()); //从大到小 
    cout << "\n从大到小 :" << endl;
    for (int i=0; i<obj.size(); i++)
    {
        cout << obj[i] << ",";   
    } 
    cout << "\n" << endl;
 
    cout << "从小到大:" << endl;
    sort(obj.begin(), obj.end()); //从小到大
    for (int i=0; i<obj.size(); i++)
    {
        cout << obj[i] << ",";   
    }    
    
    cout << "\n清除容器:" << endl;
    obj.clear();   //清除容器中所以数据
    for (int i=0; i<obj.size(); i++)
    {
        cout << obj[i] << endl;
    }    
    
    cout<<"\n"<<endl;
    cout << "实际数据个数 :" << endl;    
    for (int i=0; i<obj.size(); i++)  //size()容器中实际数据个数 
    {
        cout << obj[i] << ",";
    }
 
    //方法一 
       obj.push_back(112);
    obj.push_back(120);    
    obj.push_back(112); 
    cout << "直接利用数组:"; 
    for (int i=0; i<obj.size(); i++)
    {
        cout << obj[i] << " ";
    }
    cout << ", obj[2]=" << obj[2];

    cout<<endl; 
    cout<<"利用迭代器:" ;
    //方法二,使用迭代器将容器中数据输出(就是指针)
    vector<int>::iterator it;//声明一个迭代器,来访问vector容器,作用:遍历或者指向vector容器的元素 
    for( it=obj.begin(); it != obj.end(); it++)
    {
        cout << *it << " ";
    }
    return 0;
}

 

3. 使用模板实现泛型类型的函数和类 

/*  使用模板实现泛型类型的函数和类 */
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
 
using namespace std;
 
template <class T>
class Stack { 
  private: 
    vector<T> elems;          // 元素 
 
  public: 
    void push(T const&);      // 入栈
    void pop();               // 出栈
    T top() const;            // 返回栈顶元素
    bool empty() const{       // 如果为空则返回真。
        return elems.empty(); 
    } 
}; 
 
template <class T>
void Stack<T>::push (T const& elem) 
{ 
    // 追加传入元素的副本
    elems.push_back(elem);    
} 
 
template <class T>
void Stack<T>::pop () 
{ 
    if (elems.empty()) { 
        throw out_of_range("Stack<>::pop(): empty stack"); 
    }
    // 删除最后一个元素
    elems.pop_back();         
} 
 
template <class T>
T Stack<T>::top () const 
{ 
    if (elems.empty()) { 
        throw out_of_range("Stack<>::top(): empty stack"); 
    }
    // 返回最后一个元素的副本 
    return elems.back();      
} 
/* 模板函数 */ template <typename T> inline T const& Max (T const& a, T const& b) { return a < b ? b:a; } int main() { int i = 39; int j = 20; cout << "Max(i, j): " << Max(i, j) << endl; double f1 = 13.5; double f2 = 20.7; cout << "Max(f1, f2): " << Max(f1, f2) << endl; string s1 = "Hello"; string s2 = "World"; cout << "Max(s1, s2): " << Max(s1, s2) << endl; try { Stack<int> intStack; // int 类型的栈 Stack<string> stringStack; // string 类型的栈 // 操作 int 类型的栈 intStack.push(7); cout << intStack.top() <<endl; // 操作 string 类型的栈 stringStack.push("hello"); cout << stringStack.top() << std::endl; stringStack.pop(); stringStack.pop(); } catch (exception const& ex) { cerr << "Exception: " << ex.what() <<endl; return -1; } }

 

4. 其他容器stack, map

有序容器: vector, deque, stack, list

无序容器:set, map, multi_set, multi_map

#include <iostream>
#include <stack>
#include <string>
#include <utility>
#include <map>
using namespace std;

int main()
{
    stack <int> s;
    s.push(1);    
    s.push(2);
    s.push(3);
    s.push(4);
    s.push(11);
    
    cout << "top of the stack:" << s.top() << endl;
    cout << "the number of elements:" << s.size() << endl;
    cout << "process of pop:" << endl;
    
    while (s.empty() != true) // stack isn't empty
    {   cout << "\t\t";
        cout << s.top() << endl; //read the top of the stack    
        s.pop();  // pop, and delete the top
    }

    // key value
    map <int, string> StuInfo;
    StuInfo.insert(pair <int, string> (1, "Tom"));
    StuInfo.insert(pair <int, string> (5, "Jack"));
    StuInfo[2] = "Lily";
    StuInfo[7] = "Bruce";    
    map <int, string>::iterator it;   // 指针 
    
    for (it=StuInfo.begin(); it!=StuInfo.end(); it++)
    {
        cout << (*it).first << " " << (*it).second << endl;
    }    
        
    return 0;
}

 

posted @ 2020-09-23 23:18  LeonYi  阅读(965)  评论(0编辑  收藏  举报