- ベストアンサー
親クラスのフリをした子クラスの使い方を教えて下さい
以前、QNo.3479089でお世話になった者です。類似というか、続きの質問です。 ClassAを継承するClassBがあり、条件によって、ClassAまたはClassBをインスタンス化して使います。 (ClassBは、ClassAのメソッドの一部をオーバーライドして、ClassB固有のメソッドも追加しています) ClassA* pObj = NULL; if( ある条件 ) { pObj = new ClassA(); } else( その他の条件 ) { pObj = new ClassB(); } pObj->common_method(); これが常套手段と伺ったのですが、ClassBがインスタンス化された場合、ClassB固有のメソッドmethodBを呼び出そうとすると、「ClassAにはmethodBが存在しない」といったようなコンパイルエラーが出ます。 pObj->methodB(); // ここで、エラー それで、エラーを解消するために、「その他の条件」の時に、dynamic_castを使ってみました。 if( その他の条件 ) { ClassB* pObj2 = dynamic_cast<ClassB*>( pObj ); pObj2->methodB(); } 上記でコンパイルエラーは解消したのですが、なにか、非常にめんどくさいです。 また、ClassAのフリをした実体ClassBを使っているのだから、オーバーライドしているメソッドもdynamic_castをしないと呼び出されないような気がします。 結局、親のフリした子クラスを作成する場合、こんなにめんどくさいことをしないといけないのでしょうか? それともこのやり方はおかしいですか? この場合、どういうふうにするものなのか、教えて下さい。よろしくお願いします。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
> それなりに面倒なのはアタリマエということは、質問の方法で間違っていない、ということですか? YES. だからこそ、そんなことせずに済むような設計/実装を考えるが上策です。 それでもなお、やむを得ぬときにやる分にはかまいません。 頻繁にやらねばならんなら、設計を見直しましょう。
その他の回答 (4)
- rinkun
- ベストアンサー率44% (706/1571)
> また、ClassAのフリをした実体ClassBを使っているのだから、オーバーライドしているメソッドもdynamic_castをしないと呼び出されないような気がします。 これはC++言語の欠陥ですが、C++ではオーバーライドする予定のメソッドは親クラスでvirtual宣言しておく必要があります。 virtual宣言されたメソッドの場合、親クラスのポインタから呼び出しても実体が子クラスなら子クラスでオーバーライドしたメソッドが呼ばれます。 それで、子クラスでの追加処理というのはどのような文脈で呼んでいますか。親クラスでの通常処理に追加する形で呼ぶなら本質的には親クラスの該当メソッドをオーバーライドして追加処理する形が適当でしょう。 そうでないなら設計に問題がある可能性が高いですね。本当は親クラスでも同様の処理(ただし親クラスでは空処理で良い)が必要だとか。
お礼
ご回答、どうもありがとうございます。 virtual宣言は、こういうためにあるのですね。今まで実際の使い方がピンと来ませんでしたが、ご説明でよくわかりました。 子クラスでの追加処理は、共通処理の中で、「classBがインスタンス化される条件」の時のみ呼び出しています。 仰るとおり、親クラスでも空処理を定義すると、条件分岐がいらないし、virtual宣言しておけば、ダウンキャストも必要ないですね。 だいぶん、すっきりしてきました。ありがとうございました。
- hidebun
- ベストアンサー率50% (92/181)
「classBをインスタンス化するときの条件分岐」と 「メソッド呼び出し時の分岐条件(その他の条件)」は、 等価なものですか? そうであれば、もともとclassBにclassAのフリをさせることに無理があるように思います。 コードは、異なる処理を無理やり1つの関数に突っ込んだ、という感じになってしまうでしょう。 そうなっても相応のメリットがあれば、上記のような方式をとるのも仕方がないですが、 質問者さんの勘がNGと言っているのですよね? そういう場合、10中8,9、後から見ても、「とってつけたようなコード」にしか見えないことでしょう。 逆にメリットが極大であれば、このような細かいことは気にならないものです。
お礼
ご回答、どうもありがとうございました。 >「classBをインスタンス化するときの条件分岐」と >「メソッド呼び出し時の分岐条件(その他の条件)」は、 >等価なものですか? classBをインスタンス化するときの条件分岐と、classB独自のメソッド呼び出し時の分岐条件(その他の条件)は同じです。 ただ、ANo.2の方のお礼にも書いたとおり、classAとclassBはほとんどが同じ処理で、classBは、特別な条件の時に独自の処理を追加したもの、という感じです。 自分は、オブジェクト指向をまだまだよく理解していないので、一般的にみれば、メリットの方が大きいのかもしれません。
- PROMETHEUS
- ベストアンサー率58% (31/53)
ClassBを基底クラスの ClassAとして扱っている以上、ClassB独自のメソッドを 呼ぶのはちょっとイリーガルです。 claasA/classB、各メソッドの役割など詳細がわからないので、 正しいことはわかりませんが,クラスの設計かこの方法か 何かが間違っているのではないでしょうか。
お礼
ご回答、どうもありがとうございます。 classA/classBの役割というのは、通常はほとんどの処理が同一で、classBは、特別な条件の時に独自の処理を追加したもの、という感じです。 >クラスの設計かこの方法か >何かが間違っているのではないでしょうか。 クラス設計は、今作ろうとしているモノの仕様を熟知していて、かつオブジェクト志向設計のキャリア十数年の人のレビューを受けて、こうなったものです。方や実装した自分はC++一年目ですので、実装がオカシイということなんでしょうね。
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
何らかの目的があって基底クラスのフリをさせているんだから、 導出クラスで定義されたメソッドを呼ぶにはそれなりに面倒なのはアタリマエかと。そうでなくちゃ困るし。
お礼
早速のご回答ありがとうございました。 それなりに面倒なのはアタリマエということは、質問の方法で間違っていない、ということですか?
お礼
再度のご回答、ありがとうございます。 実装の段階になってこのようなことに気がついてしまったので、経験を積んだ方なら、初めからこんな設計にしなかったかも知れません。。 今後の参考にさせていただきます。ありがとうございました。