その反復子は、最大の利点は、容器を分離アルゴリズムすることができるということである、任意の所望のタイプであってもよいし、ポインタです。従来の考え方では、各クラスは、独自のコンテナ表示、検索、ソート機能を有していることです。慎重な分析を描画することができます:別のコンテナは、一般的に考え方は同じである同じ機能コードを実行し、それらは、1台のディスプレイのみ、クエリ、ソート機能に対応した複数の容器を抽象を消すことができませんか?これは、一般的な思考の発展の必然的な結果です。
STL(標準テンプレートライブラリ)は、ビルトインされたC ++ライブラリのサポート。それは、C ++クラステンプレートと関数テンプレートのメカニズムを利用します
:それは3つの部分から構成された容器、アルゴリズム、イテレータ。
コンテナの配列、共同で機能を表示するコンパイルコンテナリスト。
MyArrayという配列クラス初期コードを以下に示します。
//文件名:e3_1.cpp(本示例中所有头文件及源文件内容都在该文件中)
#include <stdio.h>
template<class T>
class MyArray
{
private:
int m_nTotalSize; //数组总长度
int m_nValidSize; //数组有效长度
T *m_pData; //数据
public:
MyArray(int nSize = 3)//数组默认总长度是3
{
m_pData = new T[nSize];
m_nTotalSize = nSize;
m_nValidSize = 0;
}
void Add(T value) //向m_pData添加数据
{
//同例1.1
}
int GetSize() //返回数组有效长度
{
return m_nValidSize;
}
T Get(int pos) //返回某一位置元素
{
return m_pData[pos];
}
virtual ~MyArray()
{
if(m_pData != NULL)
{
delete []m_pData;
m_pData = NULL;
}
}
};
Objectlistは、以下に示す初期のコードをMyLink。
template <class T>
struct Unit //链表单元
{
T value;
Unit *next;
};
template <class T>
class MyLink
{
Unit<T> *head; //链表头
Unit<T> *tail; //链表尾
Unit<T> *prev;
public:
MyLink()
{
head = tail = prev = NULL;
}
void Add(T &value)//向链表中添加元素
{
Unit<T> * u = new Unit<T>();
u->value = value;
u->next = NULL;
if(head == NULL)
{
head = u;
prev = u;
}
else
{
prev->next = u;
prev = u;
}
tail = u->next;
}
virtual ~MyLink()
{
if(head != NULL)
{
Unit<T> *prev = head;
Unit<T> *next = NULL;
while(prev != tail)
{
next = prev->next;
delete prev;
prev = next;
}
}
}
};
だから、どのようにmyarrayのために、MyLinkは、共通の表示機能の完了に基づいていますか?以下に示すように実際には、非常に単純な、ニーズから始まる、表示されている一般的な番号を書いて最初の逆を考えてみましょう。
template<class Init>
void display(Init start, Init end)
{
cout << endl;
for(Init mid=start; start != end; mid++)
{
cout << *mid << "\t" ;
}
cout << end;
}
初期テンプレート型パラメータは、開始が開始ポインタ、ポインタを端から端まで、そして*ポインタ++サポート業務で、ポインタです。表示機能は、間接的な関連付けが必要であり、特定の容器に直接関連していません。MyArrayというのために、initはMyLink、*ユニットの動作に相当するため、T *の動作に対応します。したがって、イテレータクラスをリードし、それは*、この例では、まだテンプレートT *またはパラメータユニットテンプレートクラスです。
以下に示す対応するイテレータクラスArrayIteratorをMyArrayという。
template<class Init>
class ArrayIterator
{
Init *init;
public:
ArrayIterator(Init *init)
{
this->init = init;
}
bool operator!=(ArrayIterator& it)
{
return this->init != it.init;
}
void operator++(int)
{
init ++;
}
Init operator*()
{
return *init;
}
};
また、二つの機能にMyArrayというクラスを追加する必要が反復の開始および終了ポインタを取得するために、終了を開始します。
T *Begin() //起始迭代指针
{
return m_pData;
}
T *End() //结束迭代指针
{
return m_pData + m_nValidSize;
}
以下の試験機能に示すように、
void main()
{
MyArray<int> ary;
for(int i=0; i<5; i++)
{
ary.Add(i+1);
}
ArrayIterator<int> start(ary.Begin());
ArrayIterator<int> end(ary.End());
cout << "数组元素为:" ;
display(start, end);
}
同様に、完全なリストイテレータクラスLinkIterator、下図のように。
template<class Init>
class LinkIterator
{
Init *init;
public:
LinkIterator(Init *init)
{
this->init = init;
}
bool operator != (LinkIterator& it)
{
return this->init != it.init;
}
void operator ++(int)
{
init = init->next;
}
Init operator*()
{
return *init;
}
};
メモリ・アレイの観点からリストの目的は、連続していないため、ポインタが変わり、そのためではない必要があり、++演算子!=、演算子*オーバーロードされたコンテンツArrayIteratorの内容はオペレータの同じ、唯一異なる内容で見ることができます書かれたINIT = INIT ++、唯一のinitことができる= INIT->次。
また、二つの機能にMyArrayというクラスを追加する必要が反復の開始および終了ポインタを取得するために、終了を開始します。
T *Begin() //起始迭代指针
{
return m_pData;
}
T *End() //结束迭代指针
{
return m_pData + m_nValidSize;
}
Objectlistテスト機能を以下に示します。
void main()
{
int m = 0;
MyLink<int> ml;
for(int i=0; i<5; i++)
{
m = i+1;
ml.Add(m);
}
LinkIterator<Unit<int> > start(ml.Begin());
LinkIterator<Unit<int> > end(ml.End());
display(start, end);
}
フュージョンイテレータクラス
カスタムアレイは、イテレータ・クラスは、容器の外側に配置され、方法論のリストイテレータイテレータ。しかし近い解析を見つけることができる:配列イテレータは、容器のアレイに適用することができ、容器は、リスト内で使用することができない、リスト反復子のみコンテナをリストに適用することができ、容器アレイに適用することができません。その特定のコンテナは、特定の反復子を持つ必要があります。したがって、クラスコンテナアプリケーションの特性に合わせて複数として内部イテレータクラスは例MyLinkするために、融合LinkIteratorコードは以下の通りです。
class LinkIterator;
template <class T>
class MyLink
{
public:
struct Unit //链表单元
{
T value;
Unit *next;
};
class LinkIterator
{
Unit *init;
public:
LinkIterator(Unit *init)
{
this->init = init;
}
bool operator != (LinkIterator& it)
{
return this->init != it.init;
}
void operator ++(int)
{
init = init->next;
cout<<"asdf";
}
Unit operator*()
{
return *init;
}
friend ostream & operator << (ostream & out, LinkIterator & A);
};
Unit *head; //链表头
Unit *tail; //链表尾
Unit *prev;
public:
MyLink()
{
head = tail = prev = NULL;
}
void Add(T &value)//向链表中添加元素
{
Unit * u = new Unit();
u->value = value;
u->next = NULL;
if(head == NULL)
{
head = u;
prev = u;
}
else
{
prev->next = u;
prev = u;
}
tail = u->next;
}
Unit *Begin()
{
return head;
}
Unit *End()
{
return tail;
}
virtual ~MyLink()
{
if(head != NULL)
{
Unit *prev = head;
Unit *next = NULL;
while(prev != tail)
{
next = prev->next;
delete prev;
prev = next;
}
}
}
};
ostream & operator << (ostream & out, MyLink<int>::LinkIterator & A)
{
//输出s的代码
out << A.init->value;
return out;
}
template<class Init>
void display(Init start, Init mend)
{
cout<<endl;
for(Init mid=start; start != mend; mid++)
{
cout<< mid << "\t" ;
}
cout<<endl;
}
int main()
{
int m = 0;
MyLink<int> ml;
for(int i=0; i<5; i++)
{
m = i+1;
ml.Add(m);
}
MyLink<int>::LinkIterator start = ml.Begin();
MyLink<int>::LinkIterator mend = ml.End();
display(start, mend);
return 0;
}
イテレータのさらなる理解
コンテナ、反復子、アルゴリズムは、関係の概略図に従います。
各容器は、対応するイテレータを有していなければならない、イテレータコンテナで共有特定のアルゴリズムは、特定のアルゴリズムは、特定の容器に取り付けられていません。アルゴリズムは、コンテナに関連付けられ、それを通して仲介としてイテレータ機能します。言い換えれば、より適切な言葉:イテレータの考え方は、イテレータによってコンテナ要素にアクセスするために、一般的な汎用アルゴリズム、アルゴリズムの準備の発展の必然的な結果です。
あなたは基本的な手順STL標準テンプレートライブラリプログラミングを描くことができます。
- コンテナエレメントが形成されています。
- 反復ポインタのニーズを削除します。
- 一般的なアルゴリズムを呼び出します。
実際には、生活の中で多くの「イテレータ」という現象があり、最終的な分析では、「一般的」な理由が必要です。このようなオンラインリソースなどの電話回線として普遍的な需要、すべての家族コンテナノードに相当し、通信機器である、とイテレータと同等です。インターネットを通じて何百万もの世帯は、彼らが必要とする情報を照会することができます。別の例としては、水道水の使用が一般的な需要の人生であり、すべての家族はまだノードに相当し、その後、水パイプラインは同等のイテレータです。
生活の一般的なニーズは非常に汎用的なソフトウェアアルゴリズムのためのコミュニケーションの様々な事業の発展に貢献しているので、イテレータの連続進歩を促進することができるようになります。したがって、私はすべての私たちの生活の多くの設計ソフトウェア以来、生命の現象を観察するために学生を願っています。あなたがソフトウェアを設計することができ、すべてのアイデアは生活の例を見つけることができれば、設計ソフトウェアは、あなたはとても退屈ではない、非常に満足して感じることができるようになります。
STLのイテレータは、5つのタイプに分かれています。
- 入力イテレータ
- 出力イテレータ
- フォワードイテレータ
- 双方向イテレータ
- ランダムイテレータ
入力イテレータ
シーケンシャル回のみお読みください。完全な関数である:デフォルトの構成及び構築することができる、コピーすることができ、または割り当てが等しいかどうかを比較することができ、前方に段階的に移動することができ、値を読み出すことができます。図メイン入力イテレータオーバーロード演算子は以下の通りです。
STL提供的主要输入迭代器是istream_iterator,支持表3.1中的所有操作,值得注意的是它的构造函数,有两种形式:
- istream_iterator() 默认的构造器,创建了一个流结束的迭代器。
- istream_iterator(istream &) 参数是输入流。含义是从输入流中读数据,当遇到流结束符时停止。
int main(int argc, char* argv[])
{
cout <<"input data : "<<endl;
istream_iterator<int> a(cin) ; //建立键盘输入流,用istream_iterator枚举整形数据
istream_iterator<int> b; //建立输入流结束迭代器
while(1)
{
cout << *a << endl; //输出整形数据调用operator*()
a ++ ; //迭代器指针指向下一个元素—>调用operator++(int)
if(a == b) //如果当前迭代器等于结束迭代器,则operator==
{ //退出while循环
break;
}
}
return 0;
}
//输出为:
input data :
1 2 3,
1
2
3
到我们只要输入的不是整数就会结束输入。
输出迭代器
只写一次,完成的功能有:能进行构造或缺省构造,能被复制或赋值,能进行相等性比较,能进行逐步前向移动,能进行写入值(*p=x,但不能读出)。输出迭代器重载主要操作符 如下所示。
STL提供的主要输出迭代器是ostream_iterator,支持表2.2中的所有操作,值得注意的是它的构造函数,有两种形式:
- ostream_iterator(ostream& out) 创建了流输出跌代器, 用来迭代out输出流。
- ostream_iterator(ostream& out, const char *delim) 创建了流输出迭代器, 用来向out输出流输出数据,输出的数据之间用delim字符串分割,也即是每向out输出流输出一个数据后,再向out输出流输出一个分隔符delim。
int main(int argc, char* argv[])
{
cout << "输出迭代器演示结果为: " ;
ostream_iterator<int> myout(cout, "\t"); //创建标准输出迭代器
*myout = 1;
myout++;
*myout = 2;
myout++;
*myout = 3;
return 0;
}
执行结果为:
输出迭代器演示结果为:1 2 3
前向迭代器
使用 输入迭代器 和输出迭代器可以基本满足算法和容器的要求。但还是有一些算法需要同时具备两者的功能。 STL本身并没有专为前向迭代器预定义的迭代器 。
双向迭代器:
具有前向迭代器的全部功能,另外它还可以利用自减操作符operator—向后一次移动一个位置。例如双向链表容器中需要的就是双向迭代器。
随机访问迭代器:
具有双向迭代器的所有功能,再加上一个指针所有的功能。包括使用操作符operator[]进行索引,加某个整数值到一个指针就可以向前或向后移动若干个位置,或者使用比较运算符在迭代器之间进行比较。
综观五种 iterator,我们发现从前到后需求越来越多5,也就是所谓的细化。这样在一切情况下都可以使用需求最细的随机迭代器,确实可以,但不好,因为过多的需求自然会降低它的效率,实际编程时应该选择正好合适的iterators 以期得到最高的效率。