ページ 11

クラスのこと

Posted: 2006年12月24日(日) 21:39
by meigin
こんにちは

取りあえずクラスを使っています。

データーを保持するクラスAをB,C,Dに継承します。
EクラスにAのポインタを保持して、B,C,Dのアドレスを渡します。

この方法ではB,C,Dそれぞれにデーターが保持されてしまいます。

データーを1つにして、B,C,Dを入れ替える方法はないんでしょうか?

Aは画像の管理です。

B,C,Dは表示のクラスです。
(マップチップの並べ方が違い、座標修正もここで行っています)

Eは、操作のクラスです。
(マウス等)

何か方法がありましたら教えて下さると嬉しいです。
お願いします。

Re:クラスのこと

Posted: 2006年12月24日(日) 22:21
by バグ
AのメンバにB、C、Dのポインタを持たせてしまうのはマズイのでしょうか?
E.Aー>B
E.Aー>C
E.Aー>D

これならデータは1つになるような気がしますが…

Re:クラスのこと

Posted: 2006年12月24日(日) 23:17
by Justy
@meiginさん
 継承は基本的に B is A のとき、Aを継承して Bを作るものです。
 Aと B~Dの関係を見る限り、このケースでは継承はふさわしくないでしょう。

 となると、B/C/Dに Aへのポインタを持たせるか、描画を行う抽象クラス Fを作って、Fが Aへのポインタを持ち、B/C/Dは Fを継承させて作る方法がいいのではないかと思います。
 で、Eは Fの持つ描画関数を使って描画する、と。


@バグさん
AのメンバにB、C、Dのポインタを持たせてしまうのはマズイのでしょうか?
 設計上、ちょっとどうでしょう。
 今後、B/C/Dのお仲間が増えたときにAにメンバ変数を増やさなければならない(ひょっとすると内部処理も)となるとAの独立性が失われていきます。

 もし、この方法をとるのであればAに1つの描画メンバ関数を追加します。このメンバ関数は引数にクラスGへのポインタ(ないしは参照)をとり、このGを使って描画を行います。
 クラスGは描画の(Aへのポインタないしは参照を引数にとる)純粋仮想関数を持つインターフェースクラスとし、B/C/DはGを継承して描画の詳細を実装するようにすれば、今後お仲間が増えてもAのクラスの変更は原則的に必要がなくなります。


 他にもテンプレートを使った手法とかいろいろありますが、実際どの方法がベストかは、まだちょっとこれだけの情報では判断しにくい、ってのが正直なところです・・・。

Re:クラスのこと

Posted: 2006年12月25日(月) 00:23
by meigin
バクさん

AにBのポインタを持たせると、
BはAのデーターをどうやって使えばいいのか解らないので
それが出来ませんでした。


Justyさん

ソースを公開しているのですが、多すぎても返って解りづらいような。
C Dに当たるクラスは入ってないです。
マップチップの並べ方が違い、6方向に対応しています。
マップが半分ずれて表示され、移動経路が6方向になります。

純仮想関数のクラスに継承しているのがBに当たります。


設計ミスをしているので、作り直そうと思っているのです。
そこで、出来なかったことも聞いてみようかなとなったわけです。
多重継承している上、意味のない継承も……。


寝ますので、明日試してみます。
色々ありがとう御座います。

Re:クラスのこと

Posted: 2006年12月25日(月) 06:48
by バグ
かなりゴチャゴチャになりそうだし、汎用性のないスマートなやり方ではないので、あまりオススメではありませんが…(;^_^A

BにAのデータを使わせるだけならば、Aの中にBを初期化するメンバ関数を追加してはどうでしょうか?

うーん、自分で書いておきながら、なんて苦し紛れな方法なんだろう…と思ってしまいましたよ(;´Д`)

Re:クラスのこと

Posted: 2006年12月25日(月) 06:54
by バグ
今、読み返すとムチャクチャな事を書いてしまった…(;´Д`)
Justyさんの言われるように、B、C、DにAへのポインタを持たせるのがベストではないでしょうか?
1つ前の私の書き込みは無視しておいてください…m(__)m

Re:クラスのこと

Posted: 2006年12月25日(月) 22:29
by meigin
Justyさん バクさん

ありがとう御座います。
上手く行きました。

思っていたより簡単でした。
継承をポインタに変えるだけで上手く行きました。

問題点も解決出来て棚からぼた餅のような嬉しさです。


継承って、思っていたのと感じが違うんですね。
AのクラスのデーターをB→C→Dと渡していけるのかと思っていたのです。
B=Cとしたら当然エラーでした。

あはは……。

Re:クラスのこと

Posted: 2006年12月25日(月) 23:24
by Justy
ソースを公開しているのですが、多すぎても返って解りづらいような
 それほど複雑な構成という訳でもなさそうなので、doxygenでパースしつつちょっと見てみました。
 継承関係からするとAは ClFightPlaceクラスで、Bは ClFourDirectionsクラスで、Cに相当するのがまだ見ぬ ClSixDirections(仮)ってところでしょうか。


上手く行きました
 それは何よりです。


継承って、思っていたのと感じが違うんですね
 継承と内包をどう使い分ければいいのか、内包も実体を持てばいいのかポインタで持てばいいのか。
 それがオブジェクト指向言語の最初の壁ですよね。

Re:クラスのこと

Posted: 2006年12月26日(火) 00:26
by meigin
Justyさん

Aに当たるのはもう一つ上です。
ClFightPlaceクラスは、抽象クラスのFになりました。

名前空間を使って関数をまとめた方が楽な様な気がするのですが、
クラスの方が良いのかな?

オブジェクト指向って難しいですね。
継承って使い所があんまりない様な……。
内包は継承と殆ど同じですよね?
(メンバ変数になるだけですよね)

うーん。

Re:クラスのこと

Posted: 2006年12月26日(火) 01:13
by Justy
Aに当たるのはもう一つ上です
 あ、そうか。Aは画像を扱うクラスでしたよね。


継承って使い所があんまりない様な……。
 んー、作る物によりけりですなところはあります。
 例えば今回の kageSだと、売り買いできる物として武器・防具・アイテムがありますよね?
 これらのクラス全てに価格というメンバ変数がありますが、「売り買い可能なものというクラス」を基底として名前とか価格をメンバ変数を入れておけば、将来お店クラスを作ったときに武器とか防具とかの生々しいクラスを個別に扱わなくても「売り買い可能なもの」クラスだけを相手にすれば売買できるようになります。

 その他インターフェースの為に継承したり、実装を引き継ぎたい為に継承したりと結構使いどころはあると思います。



内包は継承と殆ど同じですよね?
 内包という言い方がまずかったかもしれませんが、メンバ関数になるのと継承するのとでは全然違います。

 継承する場合(主に public継承)は、元のクラスの特殊版を作っていく感覚になります(特化)。
 例えばよくある例ですが、犬や猿や人は全てほ乳類であり、それらはほ乳類としての特徴を全て引き継いでいるので、ほ乳類を継承して犬や猿や人のクラスを作ることはそういう意味では正当です。

 では犬や猿や人が必ず持っている手足や頭は、というとこれはそれらが「所有」するものなので継承関係ではなく内包というか集約関係にあります。
 この場合はメンバ変数として実装するのが正当となります。


 継承の場合(public)、元のクラスの性能をそのまま引き継ぐので基底の publicメンバ関数は全て派生側でも使用できるようになります。
 もちろん継承を使わないでメンバ関数にしても、それを公開すれば同じメンバ関数を使用できるのですが、日本語で考えるといろいろ不自然さが目立ちます。
 
 例えばほ乳類は呼吸する、という動作を行う場合を想定し、ほ乳類クラスに呼吸するという関数があったとします。

 継承で作れば「人->呼吸する・・・人が呼吸する」で実行できます。
 が、集約で作ると「人->ほ乳類->呼吸する・・・人が持っているほ乳類が呼吸する」と何やら不自然さが目立ってきます。


 つたない説明ですが、こういう違いがあります。
 もっと詳しい&正確なことはhttp://www.amazon.co.jp/dp/4881356194
の本を読むと、すごくよく判ると思います。

Re:クラスのこと

Posted: 2006年12月26日(火) 07:35
by meigin
Justyさん

オブジェクトと言うのでブロックのようなイメージを持っていて、
単に繋げれば良いのかなと思っていました。

意味というか概念も考えて作らないといけないんですね。
もっと、本を読んで勉強します。

ありがとう御座います。