スポンサーリンク

C++/CLIでHashSetを使ってみる

コメントに質問があったので使用例を置いておきたい。

HashSetは等価であることを比較するためにEqualsメソッドを持っていなければならない。

全てのクラスはObjectの子クラスなので、Equalsをオーバーライドしてもいいが、IEquatableを継承するとObject型ではなく指定した型のデータをとるEqualsをオーバーライドできるようになる。

#include "pch.h"

// 自作クラス
// IEquatableを継承しているのでEqualsメソッドをオーバーライドすることで
// インスタンスの等価判定が可能
public ref class DataType : System::IEquatable<DataType^> {
private:
    int a, b;

public:
    DataType() : a(0), b(0) {}
    DataType(int _a, int _b) : a(_a), b(_b) {}

    int geta() { return a; }
    int getb() { return b; }
    void set(int _a, int _b) { a = _a; b = _b; }

    /*
    // IEquatableを使用しない場合はObject^型で受け取って評価できる
    // ObjectのEqualsメソッドをオーバーライド
    virtual bool Equals(Object^ obj) override {
        if (obj == nullptr) return false;

        DataType^ other = dynamic_cast<DataType^>(obj);
        if (other == nullptr) return false;

        return a == other->a && b == other->b;
    }
    */

    // IEquatableのEqualsメソッドを実装
    virtual bool Equals(DataType^ other) {
        if (other == nullptr) return false;
        return (a == other->a) && (b == other->b);
    }


    // ObjectのGetHashCodeメソッドをオーバーライド
    virtual int GetHashCode() override {
        return a.GetHashCode() ^ b.GetHashCode();
    }
};
      
// 比較用クラス
// IComparerを継承してCompareメソッドをオーバーライドする。
// このクラスをArray::Sortの第二引数に渡すことで、ソートの基準を変更できる。
public ref class Ccmp : System::Collections::Generic::IComparer<DataType^> {
    public:
	virtual int Compare(DataType^ x, DataType^ y) {
            if (x->geta() < y->geta()) return -1;
            if (x->geta() > y->geta()) return 1;

            if (x->getb() < y->getb()) return -1;
            if (x->getb() > y->getb()) return 1;
	}
};

void sort_test() {
    array<DataType^>^ ary = gcnew array<DataType^>(3);
    ary[0] = gcnew DataType(1, 2);
    ary[1] = gcnew DataType(6, 8);
    ary[2] = gcnew DataType(2, 4);
    //ソート実行。
    Ccmp^ cmp = gcnew Ccmp();//比較用クラスのインスタンスを作成し、
    System::Array::Sort(ary, cmp);//Array::Sortの第二引数にそのハンドルを渡す

    for each (DataType^ data in ary) {
        System::Console::WriteLine("a = {0}, b = {1}", data->geta(), data->getb());
    }
}

void hashset_test() {

    using namespace System::Collections::Generic; // HashSetを使えるようにする

    // DataTypeのHashSetを作成
    HashSet<DataType^>^ hashSet = gcnew HashSet<DataType^>();

    // DataTypeのインスタンスを作成してHashSetに追加

    DataType^ data1 = gcnew DataType(-1, 3); // 重複するデータ
    DataType^ data2 = gcnew DataType(4, 2);
    DataType^ data3 = gcnew DataType(-1, 3); // 重複するデータ
    hashSet->Add(data1);
    hashSet->Add(data2);
    hashSet->Add(data3);

    //hashSet内の全データ表示
    for each (DataType ^ data in hashSet) {
        System::Console::WriteLine("a = {0}, b = {1}", data->geta(), data->getb());
    }
}

int main(array<System::String^>^ args) { sort_test(); hashset_test(); return 0; }

実行例 sort_test()の結果

a = 1, b = 2
a = 2, b = 4
a = 6, b = 8

実行例 hashset_test()の結果

a = -1, b = 3
a = 4, b = 2

1 件のコメント

  • どうもありがとうございました。
    hashset.add()で追加する要素のクラスには、ソートの様に「比較用クラス」を指定する必要は無いのですね。
    public ref class DataType : System::IEquatable {}という定義方法が使えるというのは良い学習になりました。
    こちらでも動作確認を行い、やりたいことが実現できるようになってきました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: