自分でも主旨がよくわからないけれどもアリプラシリーズの続き。アリス・イン・ワンダーランドとプラダを着た悪魔に似ているような似てないような…という関係は後付けで。
アリスに Prada をプレゼントすると貰うけど、Tiffany をプレゼントしても貰わない、ってのが次のコードです。Prada と Tiffany のクラスを一度 dynamic_cast してみてチェックする訳ですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | // 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; } |
実行するとこんな感じ。
1 2 3 4 5 | 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 だけ、というのがロリータです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | // 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; } |
1 2 3 4 5 | 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 変数などで設定したのです。
1 2 3 4 5 6 | class Prada { protected : char *classname = "Prada" ; public : ... }; |
こんな感じで。そう、CakePHP で自前のクラス名を指定している(PHP4対策だそうです)を見て、そんなことを考えたりしました。UML で云えば、クラス変数とオブジェクト変数という違いだったり。