アリスはロリータと鞄を共有しない

引き続き、アリプラシリーズ。

ルイスが鞄をプレゼントする相手は、アリスだったりロリータだったりするわけですが、間違ってロリータにプレゼントしたものをアリスに渡したときの反応はどうでしょうか?ってな設定が次のコードです。

// for アリスはロリータと鞄を共有しない

#include <iostream>
#include <list>
using namespace std;

class Bag {
protected:
	void *_mark;
public:
	Bag() : _mark(NULL) {}
	virtual void setMark( void *mark ) {
		_mark = mark;
	}
	virtual void *getMark() {
		return _mark;
	}
};

class Prada : public Bag {};
class Tiffany : public Bag {};

class Alice
{
private:
	list<Bag*> bags;
public:
	Alice() {
	}
	void Present( Bag *bag ) 
	{
		if ( dynamic_cast<Prada*>(bag) != NULL &&
             bag->getMark() == NULL ) 
		{
			bag->setMark( this );
			bags.push_back( bag );
		}
	}
	int CountBags() 
	{
		return bags.size();
	}
};

class Lolita 
{
private:
	list<Bag*> bags;
public:
	void Present( Bag *bag ) 
	{
		bag->setMark( this );
		bags.push_back( bag );
	}
};

int main(void)
{
	Alice alice;
	Lolita lolita;
	
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Prada());
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Tiffany());
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	// 一度ロリータにあげる
	Bag *bag = new Prada();
	lolita.Present( bag );
	// そしてアリスにプレゼント
	alice.Present(bag); 
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	bag = new Prada();
	alice.Present(bag);
	cout << "alice has " << alice.CountBags() << " bags." << endl;

	// 実は、アリスにプレゼントしたものをロリータにあげることもできる
	lolita.Present( bag );

	return 0;
}

バッグ自体にマーキングを付けているので、自分の鞄かどうかは分かるので、一度ロリータにプレゼントされた鞄を拒否ることができます。

が、問題は、アリスにプレゼントした鞄はロリータによってマーキングが上書きされてしまうので、その鞄はロリータのものになってしまうんですねぇ。困った。

これを防ぐには、Bag クラスの mark の処を次のように1回だけ書くように直します。

class Bag {
protected:
	void *_mark;
public:
	Bag() : _mark(NULL) {}
	virtual void setMark( void *mark ) {
		if ( _mark == NULL ) {
			_mark = mark;
		}
	}
	virtual void *getMark() {
		return _mark;
	}
};

ええ、何処かでみたようなコピーワンスの処理ですね。似たような感じで Use メソッドの中でカウンタを減らせば、ユーズワンス、の処理も可能です。ただし、コピーワンスの機能も、コピー対象(Prada とか DVD とか)を扱うモノ(Lolita とかビデオ機器とか)が Used をきちんと呼び出さなければ、利用は可能なのです。
このあたりのコピーワンスのガードを確実に呼び出させるためには、例えば初期の暗号解読のためのキーの読み出し自体にコピーワンスのガードを入れるとか、利用に必須なものに対してガードを入れ込みます。実は似たようところでは、SNS のログイン機能とか、ゲームソフトのコピーガードの仕方とかも似た方式です。最初にガードを置きます。
なので、実は最初にガードを置かずに、本体の所々にガードを分散させるってのもアリなんですよね。確か、販売 DVD のコピーガードはこの方式になっています。

カテゴリー: C++ パーマリンク