トップ-> C++入門:7章 STL-> クラスとSTL

←前ページへ :  トップへ :  次ページへ→


  クラスのポインタ型のコンテナを作り、newしたインスタンスをコンテナに追加していくような 使い方をする場合は注意が必要です。例えば、次のような場合、vectorに代入されるのは ポインタです。したがってソートなどのアルゴリズムから呼ばれる演算子は、クラスの比較演算子ではなく、 ポインタ同士の比較演算子になります。つまり、ポインタ(アドレス)でのソートとなり、あまり 有用な使い方がなくなってしまいます。(クラスのポインタ演算子を作ることができれば、 このような事はなくなるのですが・・・。)
// この場合、ソート関数から呼ばれるのは、この演算子ではない
bool operator<(TestClass& p1, const TestClass& p2){
    return p1 < p2;
}

// このような演算子は作れない
bool operator<(TestClass*& p1, const TestClass*& p2){
    return *p1 < *p2;
}


{
    // TestClass型のvectorを作る
    vector<TestClass*>   vect;

    // vectorに代入する
    for( i = 0 ; i < 10 ; i++ )
        vect.push_back( new TestClass(i, 'A'+i) );

    sort( vect.begin(), vect.end() );
    // ソート関数内から呼ばれる比較演算子は、ポインタ同士の比較をする演算子である
    // つまり「bool operator<(TestClass*& p1, const TestClass*& p2)」という演算子であるが、
    // このような演算子はプログラマーが勝手に用意することはできない
}
  つまり、以下のサンプルではソートを行っているが、アドレス順にソートされているため、見かけ上 ソートされているようにはみえない。
#include "stdafx.h"
#include <algorithm>
#include <iostream>

// vectorを使えるようにする
#include<vector>
using namespace std;

class TestClass{
public:
	// コンストラクタ
    TestClass(int n, char ch){
        m_n  = n;
        m_ch = ch;
    }

    // 比較演算子(sortで必要)
    bool operator<(const TestClass &a)const{
        return m_n < a.m_n;
    }

    int  m_n;
    char m_ch;
};

// TestClass型のvectorを作る
vector<TestClass*>   vect(10);

//
// vectorの中身を表示する(イタレーター使用)
void disp(){
    vector<TestCclass*>::iterator	itr = vect.begin();

    cout << "vector   " << endl;
    for( ; itr != vect.end() ; itr++ )
        cout << "n = " << (**itr).m_n << "  ch = " << (**itr).m_ch << "  address:" << *itr << endl;
    cout << endl;
}

void main(){
    // vectorに追加する
    for( int i = 0 ; i < 10 ; i++ )
        vect[i] = new TestClass(i, 'A'+i);

    random_shuffle( vect.begin(), vect.end() );
    disp();

    // ソート
    sort( vect.begin(), vect.end() );
    disp();

    return;
}
vector
n = 4  ch = E  address:007E0510
n = 3  ch = D  address:007E0E70
n = 0  ch = A  address:007E0C30
n = 2  ch = C  address:007E0EB0
n = 6  ch = G  address:007E0490
n = 7  ch = H  address:007E0450
n = 8  ch = I  address:007E0410
n = 9  ch = J  address:007E03D0
n = 5  ch = F  address:007E04D0
n = 1  ch = B  address:007E0BF0

vector
n = 9  ch = J  address:007E03D0
n = 8  ch = I  address:007E0410
n = 7  ch = H  address:007E0450
n = 6  ch = G  address:007E0490
n = 5  ch = F  address:007E04D0
n = 4  ch = E  address:007E0510
n = 1  ch = B  address:007E0BF0
n = 0  ch = A  address:007E0C30
n = 3  ch = D  address:007E0E70
n = 2  ch = C  address:007E0EB0
  このような場合は、比較するための関数を自分で作成し(下の例では「small」関数)、 sort関数などから比較のために、作成した関数を呼ぶように定義する。これを関数オブジェクトと呼ぶ。

  以下の例では関数オブジェクトを利用しているため、クラスポインタのコンテナではあるが、 きちんとソートされている例である。

#include "stdafx.h"
#include <algorithm>
#include <iostream>

// vectorを使えるようにする
#include<vector>
using namespace std;

class TestClass{
public:
	// コンストラクタ
    TestClass(int n, char ch){
        m_n  = n;
        m_ch = ch;
    }

    // 比較演算子(findで必要)
    bool operator==(const TestClass &a)const{
        return m_n == a.m_n && m_ch == a.m_ch ;
    }

    // 比較演算子(sortで必要)
    bool operator<(const TestClass &a)const{
        return m_n < a.m_n;
    }

    int  m_n;
    char m_ch;
};

bool small(const TestClass* &a, const TestClass* &b){
    return *a < *b;
}

// TestClass型のvectorを作る
vector<TestClass*>   vect(10);

//
// vectorの中身を表示する(イタレーター使用)
void disp(){
    vector<TestClass*>::iterator	itr = vect.begin();

    cout << "vector   " << endl;
    for( ; itr != vect.end() ; itr++ )
        cout << "n = " << (**itr).m_n << "  ch = " << (**itr).m_ch << "  address:" << *itr << endl;
    cout << endl;
}

void main(){
    // vectorに追加する
    for( int i = 0 ; i < 10 ; i++ )
        vect[i] = new TestClass(i, 'A'+i);

    random_shuffle( vect.begin(), vect.end() );
    disp();

    // ソート
    sort( vect.begin(), vect.end(), ::small  );
    disp();

    return;
}
vector
n = 4  ch = E  address:007E0510
n = 3  ch = D  address:007E0E70
n = 0  ch = A  address:007E0C30
n = 2  ch = C  address:007E0EB0
n = 6  ch = G  address:007E0490
n = 7  ch = H  address:007E0450
n = 8  ch = I  address:007E0410
n = 9  ch = J  address:007E03D0
n = 5  ch = F  address:007E04D0
n = 1  ch = B  address:007E0BF0

vector
n = 0  ch = A  address:007E0C30
n = 1  ch = B  address:007E0BF0
n = 2  ch = C  address:007E0EB0
n = 3  ch = D  address:007E0E70
n = 4  ch = E  address:007E0510
n = 5  ch = F  address:007E04D0
n = 6  ch = G  address:007E0490
n = 7  ch = H  address:007E0450
n = 8  ch = I  address:007E0410
n = 9  ch = J  address:007E03D0
  このように関数オブジェクトを使用して、比較などをすでに定義されている演算子などを利用しない 方法を用いることで、クラスポインタ型のコンテナを利用する。

  ソート関数は関数オブジェクトを使用できるが、検索を行う「find」関数は、関数 オブジェクトを使用できない。この場合は「find_if」関数を用いればよい。このように アルゴリズムに定義されている関数には、関数オブジェクトを利用できる関数と、「○○_if」という 関数オブジェクトを使用するための専用の関数が用意されているのでそちらを使う。   


←前ページへ :  トップへ :  次ページへ→