Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What is going on with this article?
@_meki

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

More than 3 years have passed since last update.

概要

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

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

修正履歴

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

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

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

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

コード例
#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 を使い回すことできます。

コード例
#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 を委譲することでイテレータを使い回すことができます。

コード例
#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 も同じ要領で実装できます。

コード例
#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 << " "; }
}
5
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
_meki

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
5
Help us understand the problem. What is going on with this article?