自作クラスで簡単に拡張 for 文を使える例いくつか

# 概要

自作クラスで少しのコードで拡張 for 文（イテレータ）を使える例をいくつかまとめます。
自作クラスでイテレータというとなんだか自分で１から実装しなくちゃいけない気がして憂鬱ですが、実際は以下のパターンのどれかが使える場合が案外多く、少しのコード追加だけで拡張 for 文やSTLのアルゴリズムが使えるようになるので便利です。

（なお、以下の例では全体的に `std::vector` を使って書いていますが、 `std::list, std::map` などでも同じですので適宜読み替えて下さい）

## 修正履歴

- 2017/05/15 : 「STL コンテナを public 継承した場合」セクションのコードミスを修正しました。

## STL コンテナを public 継承した場合

STL コンテナを public 継承した場合には、特に何もしなくても親クラスのイテレータがそのまま使えるので拡張 for 文が使えます。ただし、 STL コンテナのデストラクタには virtual がついていないので取り扱いには注意(*)が必要です。よく継承でなくコンポジションを使うようにと推奨されています。

(*) 例えば親クラスのポインタにアップキャストして delete すると子クラスのデストラクタが呼ばれないなど。

```cpp:コード例
#include <iostream>
#include <vector>
using namespace std;

using VectReal = std::vector<double>;

class MyVect : public VectReal
{
public:
    MyVect(std::initializer_list<double> list)
        : VectReal(list)
    { }
};

int main(void)
{
    MyVect v = { 1, 2, 3, 4, 5 };
    for (double d : v) { cout << d << " "; }
}
```

```:コンソール出力
1 2 3 4 5
```

## STL コンテナを private 継承した場合

private 継承した場合、親クラスのメンバはすべて private になるため、そのままでは拡張 for 文は使えません。ですが下記のように必要なメンバの using 宣言を追加することで親クラスのイテレータや `begin, end` を使い回すことできます。

```cpp:コード例
#include <iostream>
#include <vector>
using namespace std;

using VectReal = std::vector<double>;

class MyVect : private VectReal
{
public:
    /* 親クラスのイテレータを使うために iterator, const_iterator, begin, end を using する */
    using VectReal::iterator;
    using VectReal::const_iterator;
    using VectReal::begin;
    using VectReal::end;
    // ...その他使いたいメソッド・メンバ・typedef を using する

    MyVect(std::initializer_list<double> list)
        : VectReal(list)
    { }
};

int main(void)
{
    MyVect v = { 1, 2, 3, 4, 5 };
    for (double d : v) { cout << d << " "; }
}
```

```:コンソール出力
1 2 3 4 5
```

## STL コンテナをコンポジションした場合

STL コンテナをコンポジション（メンバ変数として保持）した場合も、そのままでは拡張 for 文は使えません。しかしコンポジションしたメンバ変数に対して `begin, end` を委譲することでイテレータを使い回すことができます。

```cpp:コード例
#include <iostream>
#include <vector>
using namespace std;

using VectReal = std::vector<double>;

class MyVect
{
public:

    MyVect(std::initializer_list<double> list)
        : m_vect(list)
    { }
    
    // iterator, const_iterator の typedef をしておくと MyVect::iterator と書けて便利（必須ではない）。
    using iterator = VectReal::iterator;
    using const_iterator = VectReal::const_iterator;
    
    // m_vect に処理を委譲
    iterator begin() { return m_vect.begin(); }
    iterator end() { return m_vect.end(); }
    const_iterator begin() const { return m_vect.begin(); }
    const_iterator end() const { return m_vect.end(); }
    
    
private:
   // コンポジション
   VectReal m_vect;
};

int main(void)
{
    MyVect v = { 1, 2, 3, 4, 5 };
    for (double d : v) { cout << d << " "; }
}
```

```:コンソール出力
1 2 3 4 5
```

## ポインタ配列をメンバに持つ場合

ポインタ配列をメンバに持つ場合にも、①ポインタをイテレータとして typedefして、② `begin, end` を下記のように実装すれば簡単に拡張 for 文が使えます。 `rbegin, rend` も同じ要領で実装できます。

```cpp:コード例
#include <iostream>
#include <vector>
using namespace std;

class MyVect
{
public:

    MyVect(std::initializer_list<double> list)
    {
        m_size = list.size();
        m_vect = new double[m_size];
        std::copy(list.begin(), list.end(), m_vect);
    }
    
    using iterator = double*;
    using const_iterator = const double*;
    
    iterator begin() { return m_vect; }
    iterator end() { return m_vect + m_size; }
    const_iterator begin() const { return m_vect; }
    const_iterator end() const { return m_vect + m_size; }
    
    
private:
   double* m_vect;
   size_t m_size;
};

int main(void)
{
    MyVect v = { 1, 2, 3, 4, 5 };
    for (double d : v) { cout << d << " "; }
}
```