- 締切済み
関数を引数とする方法?
いつもお世話になっています。 MFCでプログラムをしています。 今、任意の関数(Func1)を 積分する関数(Func2)を作っています。 現在は、被積分関数の数だけ、 積分関数(Func2)を書いているのですが、 非効率的なので、なるべく汎用性を持たせたいと 考えています。 参考書(新C言語入門シニア編)の該当個所で、 クラスでない通常の関数を引数とする場合は、 うまくいったのですが、 クラスのメンバ関数を引数とした場合、 どうしてもコンパイルエラーが 発生してしまいます。 関数Func、I及びエラーメッセージは大凡次のとおりです。今のところ、引数とする関数(Func1)の引数は、 同一個数としています。 <被積分関数の例> double ClassA::Func1 (double a){ return a * 10; } <積分関数> double ClassA::Func2 (double (*f)(double), double a, double b){ return b * f(a); } void classA::Integration() { ... Func2(Func1,a,b); ... } <エラーメッセージ> classA::Integrationの呼び出し箇所で、 「1番目の引数を double(double)からdouble(__cdecl)(double)に 変換できません」 と出ます。 double(double)の部分は合っているようなのですが、 (__cdecl)の部分が違うということまでは 分かりました。 メンバ関数であることが原因のようなので、 Func2での引数宣言を double ClassA::Func2 (double (ClassA::*f)(double), double a, double b){ return b * f(a); } に変えてみたところ、 引数受け渡しのところはクリアするのですが、 Func2(Func1,a,b); の呼び出し時に、Func2が関数ではないという エラーがでます。 アドバイス又は参考URL等を 教えていただければ助かります。 よろしくお願いします。
- みんなの回答 (4)
- 専門家の回答
みんなの回答
- a-kuma
- ベストアンサー率50% (1122/2211)
> 注解 C++ リファレンスマニュアル > は、持ってませんでした。 > > 辞書代わりに1部署に1冊という必須の > 書籍のようですので、 > 購入しようと思います。 ちょっと古い本だ、ということを頭に置いて読んでくださいね。 # 蛇足かも知れませが (^^;
- a-kuma
- ベストアンサー率50% (1122/2211)
> 上記のようなテクニックについて > 参考書等を紹介して頂けると > ありがたいです。 先の回答は、テクニックでもなんでもなくて、c++ の仕様どおりの動きだったり します。私が c++ を始めたときは、まだ、ANSI の規格が定まっていないとき だったので、それまでのバイブル ARM という本(邦題は 注解 C++ リファレンス マニュアルだったかな)でした。 で、ANSI の規格が出た後に、その内容を読んだくらい。 因みに、No.2 で mickjey2 さんが *より c++ らしく* とあるので、私も一筆。 積分をするということなので、積分対象の関数と、積分をするクラス、と しましょうか。 一応、積分対象の関数の形を決めるのは、積分をするクラスでしょうから、 こんな感じになるかな。 class Integration { private: func& func; public: class func { public: virtual double f(double) = 0; }; Integration(func& f) : func(f) {} double calc(double x_min, double y_min); }; // 使う側 class test_func : public Integration::func { private: double a_, b_; public: test_func(double a, double b) : a_(a), b_(b) {} double f(double x) { return (x - a_) * (x - a_) - b_; } }; int main() { test_func t(10.0, 20.0); Integration integration(t); cout << integration.calc(-1.0, 1.0) << endl; return 0; } 因みに、こういうのを「デザインパターン」では、Strategy パターン、と言います。 # 質問にある Func2 のように、長方形か台形かを隠す関数の導入も、この # 調子でいけます
せっかくC++で書くのであれば、もっとC++を生かした方法のほうがよりよいと思うのですが。 class A { public: double Func2(double a, double b); protected: virtual double Func1(double a) = 0; } と純粋クラスを作成して(Func2内では純粋クラスのFunc1を呼び出して値を得る)、 必要なFunc1毎にclass Aの派生クラス Bを作ればよいわけです。 class B : public A { protected: double Func1(double a); } B::Func1(double a) { 関数処理 } 派生クラスのインスタンスでは基底クラスA の Func2 は派生クラスB のFunc1を呼び出します。 main{ B obj; cout << "integ( -0.1, 0.1 ) = " << obj.Func2(-0.1, 0.1) << endl; } 関数ごとにクラスを作って、Func1だけオーバーライドすればよいから最低限の加工で済みます。
お礼
mickjey2様 アドバイスありがとうございました。 すごいです。 参考書では、 何度も目にした仮想関数ですが、 実際に応用した例を見たことがなかったので、 感動しました。 これは、めちゃめちゃ使えます!! 今後ともよろしくお願いします。
- a-kuma
- ベストアンサー率50% (1122/2211)
メンバー関数のポインタというところが味噌なんですね。 まずは、 > Func2(Func1,a,b); > > の呼び出し時に、Func2が関数ではないという > エラーがでます。 に対する答えは、こう。 Func2(classA::Func1, a, b); で、次に引っかかるであろうところが、classA::Func2 の > return b * f(a); のところ。 メソッドのポインタは、陽にオブジェクトを指定してあげなくてはいけません。 こんな感じ。 return b * (this->*f)(a); 以上を踏まえて、簡単なプログラムを書いてみました。 #include <iostream.h> class classA { public: double Func1(double); double Func2(double (classA::*)(double), double, double); void Integration(); }; double classA::Func1(double a) { return a * 10.0; } double classA::Func2( double (classA::*f)(double), double a, double b ) { return b * (this->*f)(a); } void classA::Integration() { double x; x = Func2(classA::Func1, 10.0, 20.0); cout << x << endl; } int main() { classA a; a.Integration(); return 0; } # あと、ちょっとだったですね :-)
お礼
a-kuma様 アドバイスありがとうございます。 ばっちりうまく行きました。 本当にありがとうございました。 上記のようなテクニックについて 参考書等を紹介して頂けると ありがたいです。 今後ともよろしくお願いします。
お礼
a-kuma様 アドバイスありがとうございます。 注解 C++ リファレンスマニュアル は、持ってませんでした。 辞書代わりに1部署に1冊という必須の 書籍のようですので、 購入しようと思います。 ありがとうございます。 後半のプログラミングについては、 私には少し難しかったのですが、 mainを見ると、 被積分関数の係数a,bを指定してから、 積分する方法だということは分かり、 とても参考になりました。 もう少し、じっくり研究したいと思います。 本当にどうもありがとうございました。 今後ともよろしくお願いします。