- ベストアンサー
オーバーライド関数の呼び出し元を判定するにはどうしたらよいでしょうか?
オーバーライド関数の呼び出し元を判定するにはどうしたらよいでしょうか? 基底クラスはCPropertyPageで、そこから複数階層まで継承しています。 末端クラスの関数が呼ばれたとき、それがどの派生クラスから呼ばれたかによって処理を分けたいのですがどうしたら良いでしょうか?
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
#2です。 > GetObject()でなんとかならないかなぁと考えています。 こういうのは「型スイッチ」といって、典型的な禁じ手のひとつです。 どうしてもそれ以外の実現方法がないとか、禁じ手をおかすことで多大なメリットが得られるならともかく、今回の場合はそのようには思えません。 > 既存のソース(基底クラス)は出来ればあまり触りたくないので・・・ だったら非メンバの関数テンプレートを作るとか、もっとよい方法がいろいろあると思います。
その他の回答 (5)
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
「親クラス」の定義が曖昧ですが、C++の基底クラスではないのですか? 状況がわかりませんので、基本的な方針を。 「呼び出し元の情報が欲しければ、呼び出し元でセットしてもらえ」 これが、基本です。 この場合だったら、FuncA(CObject *wk) という形にして、呼び出す方からセットしてもらえば、問題ありません。 もしも、スコープの関係か何かで、呼び出し元で、セットできないとしたら、「呼び出し元とそのオブジェクトの関係」をどう定義するかで、いずれにしても、関連する情報があるはずです。それをセットすればいいです。(オブジェクトの識別名とか)
お礼
分かりにくい説明に何度も回答頂きありがとうございます。 > この場合だったら、FuncA(CObject *wk) という形にして、呼び出す方からセットしてもらえば、問題ありません。 FuncAに該当する関数がたくさんあり、また色んなところから呼ばれているので影響範囲が大きいので頭が痛いです・・・ > 「呼び出し元の情報が欲しければ、呼び出し元でセットしてもらえ」 でもこれが【基本】なのですよね、頑張ってみます。ありがとうございました。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
No.3 です。もしも、「オーバーライドに限る」(仮想関数は使えない/使いたくない)というのであれば、基底クラス側を書き直す必要があります。 少なくとも、 CObject* 派生クラスA::GetObject(void) は、派生クラスA(または、そのさらに派生クラス)からしか呼び出されませんから、ここでどうあがいても無理です。 --- void 基底クラス::FuncA() { FuncB(objectA); } void 基底クラス::FuncB(CObject *pObj) { // FuncA の GetObject() 呼び出し以降に元々あった処理 …… } --- void 基底クラス::FuncA() { FuncB(objectAA); } } こんな感じです。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
一応、どのクラスから呼ばれたかを識別する方法はないことはありません。 ただ、言い換えると、「クラスが増えるたびに書き直しをしなければならない」ということで、普通はあまりいい方法ではありません。それに、派生クラスで定義した関数を、基底クラスから呼び出すことはできないはずですが。 設計が間違っていなければ、この場合、仮想関数にするのは、GetObject() の方です。 --- virtual CObject* 基底クラス::GetObject(void) { return objectA; } void 基底クラス::FuncA() { // FuncA() は、「ふさわしいオブジェクト」を作って…… CObject *pObj = GetObject(); // それ以降の「共通の処理」をする。 } --- virtual CObject* 派生クラスA::GetObject(void) { return (自分のクラスで返したいオブジェクト); } また、おそらくは、 --- virtual CObject* 基底クラス::GetObject(void) = 0; // 純粋仮想関数にする void 基底クラス::FuncA() { CObject *pObj = GetObject(); …… } --- virtual CObject* 派生クラスA::GetObject(void) { return (自分のクラスで返したいオブジェクト); } // 各クラスで、ふさわしいオブジェクトを返す のほうが、全体の設計がすっきるするはずです。
補足
すみません、私の説明不足です。 ・基底クラスというか親クラスです。 ・仮想関数は、GetObject()です。 派生クラスAのGetObject()が呼ばれたときは、その呼び出し元に応じて「objectAA」或いは「objectBB」を返したいです。 派生クラスA内の関数からGetObject()がコールされた場合は「objectAA」、親クラスからコールされたときは「objectBB」といった具合です。
- jacta
- ベストアンサー率26% (845/3158)
それこそ仮想関数をオーバーライドすればよいのでは?
補足
補足します。 仰るように、FuncA()を派生クラスにも持てば良いのかもしれませんが GetObject()以降に続く処理が全く同じために(しかも長い)、 GetObject()でなんとかならないかなぁと考えています。 既存のソース(基底クラス)は出来ればあまり触りたくないので・・・ --- CObject* 基底クラス::GetObject(void) { return objectA; } void 基底クラス::FuncA() { CObject *pObj = GetObject(); ・・・ } --- CObject* 派生クラスA::GetObject(void) { if (...) { // 基底クラスから呼ばれたとき // objectAAを返したい return objectAA; } else if (...) { // 派生クラスから呼ばれたとき // objectAAを返したい return objectBB; } }
- magicalpass
- ベストアンサー率58% (378/648)
関数がオーバーライドされているのなら、クラスを指定して呼び出さない限りはそのクラス内のオーバーライド関数が呼び出されるだけだと思いますが。 オーバーライドされていないのなら継承クラスからは基底クラスの関数が呼び出されるでしょうけど。 以下、「オーバーライドでない」関数の呼び出し元を判定する方法。 (1)基底クラスから継承クラスまでそれぞれ固有の値を持つメンバ変数を用意する。 (2)継承される関数の引数にそのメンバ変数を渡すようにする。 以上で呼び出し元のクラスは判明するはずですが。
お礼
説明が悪くて申し訳ないです。 他の方への補足にあるとおりの状況です。 回答ありがとうございました。
お礼
> こういうのは「型スイッチ」といって、典型的な禁じ手のひとつです。 そうなのですね・・・ 継承しているクラスではいろんな人が手を加えて、ぐちゃぐちゃになっていて、出来れば触りたくないと考えてしまいました。 メンテのし易さも考え、今後方法を検討していきます。ありがとうございました。