自分でも主旨がよくわからないけれどもアリプラシリーズの続き。アリス・イン・ワンダーランドとプラダを着た悪魔に似ているような似てないような…という関係は後付けで。
アリスに Prada をプレゼントすると貰うけど、Tiffany をプレゼントしても貰わない、ってのが次のコードです。Prada と Tiffany のクラスを一度 dynamic_cast してみてチェックする訳ですね。
// for アリスはプラダの鞄を蒐集する #include <iostream> #include <list> 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 ( 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; alice.Present(new Prada()); cout << "alice has " << alice.CountBags() << " bags." << endl; alice.Present(new Tiffany()); // ★ 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 2 bags.
3番目に Tiffany をプレゼントしていますが受け取って貰えません。贅沢者です。
一方で、鞄ならなんでも受け取るけど、見せるときは Prada だけ、というのがロリータです。
// for ロリータはプラダの鞄だけを見せる #include <iostream> #include <list> 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 Lolita { private: list<Bag*> bags; public: void Present( Bag *bag ) { bags.push_back( bag ); } list<Bag*> LookBags() { list<Bag*> temp; for ( list<Bag*>::iterator it = bags.begin(); it != bags.end(); ++it ) { if ( dynamic_cast<Prada*>(*it) != NULL ) { temp.push_back(*it); } } return temp; } }; int main(void) { Lolita lolita; cout << "lolita has " << lolita.LookBags().size() << " bags." << endl; lolita.Present(new Prada()); cout << "lolita has " << lolita.LookBags().size() << " bags." << endl; lolita.Present(new Tiffany()); cout << "lolita has " << lolita.LookBags().size() << " bags." << endl; lolita.Present(new Prada()); cout << "lolita has " << lolita.LookBags().size() << " bags." << endl; return 0; }
D:\work\blog\src\alice>a lolita has 0 bags. lolita has 1 bags. lolita has 1 bags. lolita has 2 bags.
ロリータの場合は、Present された鞄は bags にため込むけど、いざ LookBags で見せてもらうと、Prada に一致するものしか見せません。
このクラスを判別する方法ですが、C# だと 変数名 as クラス名 でキャストをしてチェックができます。他にも GetType なりでチェックする方法もあります。
ここで面白いのは、クラス名がクラスの属性のひとつとなっているところで、Prada クラスか Tiffany クラスで作られたオブジェクトを判別するのに、オブジェクトの属性ではなく、クラスそのものの属性というのがミソですね。
例えば、JUnit では Test というメソッドをリフレクションで拾う訳ですが、C# だと [TestCase] という形で属性を与えます。その昔はこのような考え方がなかったので、クラスを判別するときは明示的にクラス名を protected 変数などで設定したのです。
class Prada { protected: char *classname = "Prada"; public: ... };
こんな感じで。そう、CakePHP で自前のクラス名を指定している(PHP4対策だそうです)を見て、そんなことを考えたりしました。UML で云えば、クラス変数とオブジェクト変数という違いだったり。