OS XP
VC++ 6.0
2種類のクラスの下に同じ名前でメソッドを作ります
そのメソッドをポインタで指定して呼び出すことができるのでしょうか?
Class CA
{
Tashizan() ;
}
Class CB
{
Tashizan() ;
}
//実体化
CA fA;
CB fb;
function F[] = {fA,fB} ; // 関数の配列みたいなものをつくりたいと思います
F[0].Tashizan() ;//<----こんな感じで呼び出したいとおもいます
こーいう質問が出るということはクラス設計についてよく判っていないという証明
無関係なクラス同士ではできない(意味がないというか、必然がない)
class 年齢 { void 計算(); }; と
class 軌道 { void 計算(); }; があって同じように使える必然があると思うかい?
同一基底クラスから派生させたクラスで、基底クラスにある仮想関数を使えばいい
class b {
virtual void Tashizan();
};
class x : public b { ... };
class y : public b { ... };
のように。
でもこの場合わざわざ関数ポインタ化する理由もないしそのまま使えばいい
tetrapodさん、レスありがとうございます。
おっしゃる意味は、わかるのですが、ちょっと私の説明不足のような、
感じがするので補足します。
メソッドを”車のドアを開け方”とします。
(ドアの開け方は車の種類によって違うとします)
それぞれの車の種類ごとにクラスを定義するとして、
function car[]={マーチ、カローラ、フィット};// <---- イメージです。
for (int i = 0 ; i < 3; i ++) {
car[i].車のドアを開ける() ; // <---- イメージです。
}
(*実際のコーディングで2バイト文字はコメント以外に使えません)
というようにすると、配列の内容を変えるだけでよい、プログラムが作成できると思う
のです。
その疑似コード、説明になってません。
> function car[]={マーチ、カローラ、フィット};
型は関数なのに要素が車? なんで?
> car[i].車のドアを開ける() ;
これだと型は関数じゃなく車やん。
C# の multicast delegate を C++ でもやりたいっていう場面は
たまにありますよね。GUI を扱ってる時など特に。
まず tetrapod さんのアドバイスを参考にすると,こんな感じになります。
クラス設計さえ整理すれば,本当に関数ポインタ化なんて不要。
class ACar { public: virtual void openDoor(int how /* = どんだけ開けるか?みたい
な */ ) = 0; } ;
class CMaachi : public ACar { /* それぞれ openDoor() を実装 */ };
class CKarora : public ACar { ... };
class CFuitto : public ACar { ... };
int main()
{
CMaachi maachi;
CKarora karora;
CFuitto fuitto;
ACar* cars[] = {&maachi, &karora, &fuitto};
for (int i = 0; i < 3; ++i)
cars[i]->openDoor(0);
}
それでも,どうしても共通の親クラス ACar を持てないという事情は
よくあると思います。大人の事情ってやつですね。
そんな場合は,こういう事が出来ます。
class CMaachi { /* それぞれ別々に openDoor を持ってる */ };
class CKarora... class CFuitto...
/*! Invokable インタフェース */
class Invokable {
public: virtual void invoke(int) = 0;
};
/*! Delegate クラステンプレート */
template<typename T>
class Delegate: public Invokable {
public:
typedef void (T::*FuncType)(int);
T& body_;
FuncType func_;
Delegate(T& body, FuncType func) : body_(body), func_(func) { }
virtual void invoke(int how) {
(body_.*func_)(how);
}
};
/* 使う */
int main()
{
CMaachi maachi;
CKarora karora;
CFuitto fuitto;
Invokable* them[] = {
new Delegate<CMaachi>(maachi, &CMaachi::openDoor),
new Delegate<CKarora>(karora, &CKarora::openDoor),
new Delegate<CFuitto>(fuitto, &CFuitto::openDoor),
};
// ちなみにこの them の変数名ですが,cars はもはやふさわしくありません。
// 車ではなく,車のドアを開ける関数の「実行環境」とでも言うべきものを指して
いるので。
for (int i = 0; i < 3; i++)
them[i]->invoke(0);
// 後で delete を忘れずに!
}
これで正しく動くと思いますが,実は自信が無かったりして。
(それに「大人の事情」という縛りがあるレベルのプロジェクトだと
こういうのもレビューで弾かれたりするんですよね。
(そんなプロジェクトでは,boost::function なんて夢のまた夢。。。))
仮想関数自体が関数ポインタみたいなものなので、「同じ名前のメソッド」を同
じ呼び出しで呼び分けたい場合は、関数ポインタを使うより仮想関数をそのまま
使う方が楽で確実だと思います。
クラスの静的でないメソッドを呼び出す場合は、通常クラスのインスタンスを指す
ポインタも同時に必要になってしまうので、本当に「関数ポインタ」で実装するの
は余りお勧めできません。
#include <stdio.h>
class car {
public:virtual void door_open()=0;
};
class car_a : public car { public:virtual void door_open(){puts(car_a);} };
class car_b : public car { public:virtual void door_open(){puts(car_b);} };
class car_c : public car { public:virtual void door_open(){puts(car_c);} };
int main(int,char**){
car* cars[]={new car_a(),new car_b(),new car_c()};
for (int i = 0 ; i < 3; i ++) {
cars[i]->door_open();
}
return 0;
}
ではダメなのですか?(開放していないとかは除いて)
> メソッドを”車のドアを開け方”とします。
> (ドアの開け方は車の種類によって違うとします)
> それぞれの車の種類ごとにクラスを定義するとして、
まさに、そういうことを実現したのが
抽象クラスや仮想関数と俺は考えている。
メンバ関数へのポインタというのもあるけど
実際はイメージがかなり違いますよ。
配列および呼び出しはポインタでなければいけないけどね。
以下はイメージです。
Cマーチ oマーチ;
Cカローラ oカローラ;
Cフィット oフィット;
C車 *car[]={&oマーチ, &oカローラ, &oフィット};
for (int i = 0 ; i < 3; ++i) {
car[i]->車のドアを開ける();
}
επιστημηさん、pseudo さん、麩さん、wclrp ( 'o')さんレスありがとうございまし
た。
επιστημηさん、すいません、かなり私の勝手な表現をつかって、私のやりたいことの説
明をしているので、なかなかうまく伝わらなくて申し訳ありません。
しかし、pseudo さん、麩さん、wclrp ( 'o')には、ほぼうまくつたわったみたいです。
「仮想関数を定義して、それぞれのクラスで仮想関数オーバライドして、親クラスの配
列をとる」といいみたいですね。
みなさん、ありがとうございました。
このような、用法があるのは、知りませんでした。とても助かりました。