C++泛型編程原理


1.什么是泛型編程
前面我們介紹的vector,list,map都是一種數據結構容器,
容器本身的存儲結構不同,各容器中存在的數據類型也可以不同。
但我們在訪問這些容器中數據時,擁有相同的方式。
這種方式就叫做“泛型編程”,顧名思義,不同的類型采用相同的方式來操作

2.泛型編程的原理。
我們先看下面的兩個分別訪問數組和鏈表中元素的示例。
示例1,數組類型遍歷

void show(double* arr,int n)
{
    for(int i=0;i<n;i++)
        cout<<arr[i]<<" ";
}

示例2,鏈表類型遍歷

struct Node
{
    double item;
    Node * p_next;
};
void show(Node* head)
{
    for(Node* start=head;start!=0;start=start->p_next)
        cout<<start.item<<" ";
}

我們可以看到,數組和鏈表的訪問方式是完全不同的
那么,如何使用相同的方式去訪問呢?
這兩種數據結構的共同點是,它們都是一個順序存儲數據的容器,
所以我們可為每一種容器中定義一個相應的指針類p,在泛型編程中,叫做“迭代器類(iterator)”
該指針類中需要重載兩個操作符,
1)*p,訪問數據元素內容
2)p++,訪問下一個數據元素
示例1,數組容器(double *本身具有*p,p++操作符):

typedef double* iterator;
void show(iterator head,int n)
{
    int i=0;
    for(iterator start=head;i<n;++start)
    {
        cout<<*start<<" ";
        i++
    }
}

示例2,鏈表容器:

struct Node
{
    double item;
    Node * p_next;
};
class iterator
{
    Node *pt;
public:
    double operator*()
    {
        return pt->item;
    }
    iterator& operator++()
    {
        pt=pt->p_next;
        return *this;
    }
};
void show(iterator head)
{
    for(iterator start=head;start!=0;++start)
    {
        cout<<*start<<" ";
    }
}

我們看到這兩種容器的show()方法已基本相同,唯一的區別是結束判斷
在數組中,根據數組長度來判斷結尾。
在鏈表中,根據最后一個元素指向的下一個元素指針為空來判斷。
鏈表比數組多出來一個指向null的指針。

在泛型編程中,使用了“超尾”的概率來解決這個問題,
“超尾”是指在容器的最后一個元素后面,還有一個額外的元素,該元素表示結束。
這樣數組和鏈表都有這個超尾指針。我們統一使用這個超尾指針來判斷結尾。

3.泛型編程中迭代器的使用
C++為每個容器類(vector,list,deque等)定義了相應的迭代器類型,
其begin()返回指向第一個元素的迭代器,end()返回指向超尾元素(額外添加的元素)的迭代器。
如下例所示:

vector<double>::iterator pr;
for(pr=scores.begin();pr!=scores.end();pr++)
    cout<<*pr<<endl;

在C++11中,簡化了迭代器類型的定義,使用auto自動類型

for(auto pr=scores.begin();pr!=scores.end();pr++)
    cout<<*pr<<endl;

4.建議使用的遍歷方式
很多語言,如C#,並沒有使用迭代器iterator,而是使用for,foreach等來遍歷數據元素。
所以,C++中最好也避免直接使用迭代器,而盡可能使用for_each()
C++11中,新增了for循環,如下例所示:

for(auto x:scores)
    cout<<x<<endl;

 

參考資料:《C++ Primer.Plus》 pp.685-688


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM