更にアリプラシリーズ。
同じ鞄をプレゼントした場合は、アリスは貰わない…と言いますから、同じ鞄なんだからなんでもう一度プレゼントするの?というコードです。
// for アリスは同じ鞄を抱えない
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class Bag {
protected:
bool used;
public:
virtual bool getUsed() { return used; }
virtual void Used() { this->used = true; }
};
class Prada : public Bag {};
class Tiffany : public Bag {};
class Alice
{
private:
list<Bag*> bags;
public:
Alice() {
}
void Present( Bag *bag )
{
if ( find(bags.begin(),bags.end(),bag) == bags.end() &&
dynamic_cast<Prada*>(bag) != NULL ) {
bags.push_back( bag );
}
}
int CountBags()
{
return bags.size();
}
};
int main(void)
{
Alice alice;
cout << "alice has " << alice.CountBags() << " bags." << endl;
Bag *bag = new Prada();
alice.Present(bag);
cout << "alice has " << alice.CountBags() << " bags." << endl;
alice.Present(new Tiffany());
cout << "alice has " << alice.CountBags() << " bags." << endl;
alice.Present(bag); // 同じものをプレゼントする
cout << "alice has " << alice.CountBags() << " bags." << endl;
alice.Present(new Prada());
cout << "alice has " << alice.CountBags() << " bags." << endl;
return 0;
}
実行するとこんな感じ。
D:\work\blog\src\alice>a alice has 0 bags. alice has 1 bags. alice has 1 bags. alice has 1 bags. alice has 2 bags.
プレゼントすると、一度、タンス(bags)を find 関数で照合します。何故か知らないけど、タンス(bags)にあったものが再び Present される訳で、変なのという感じなのですが、bags には追加しません。
データベースで言うところの、同じ名前だったらデータベースに insert しない処理ってのと同じですね。
SELECT @COUNT = count(*) FROM bags WHERE ... IF @COUNT = 0 THEN INSERT bags VALUES ( ... ) END IF
のようなものです。重複チェックをして挿入ってな具合。これは、bags にある量が多くなるとだんだんと遅くなっていきます。いわゆる O(n) の確率。ただし、find のアルゴリズムを変えていけば O(log n) だっけ? になります。ハッシュテーブルとかバイナリツリーとかを使います。大変ですよね。不安ですね。
しかし、ちょっと工夫すると、一発で貰った鞄かどうかが分かります。Bag クラス自体にマーキングを示す mark 変数を用意して、これに自分のポインターを入れておきます。そうすると、mark を調べるだけで一発で分かりますよね。
class Bag {
protected:
void *_mark;
public:
Bag() : _mark(NULL) {}
virtual void setMark( void *mark ) {
_mark = mark;
}
virtual void *getMark() {
return _mark;
}
};
特性を知って、ちょっとクラスに工夫を加えるとうまくいくっていうパターンです。
