
関数ポインタの使い方で悩んでいます。
下記の
(1)のようにグローバルメソッドとして定義したメソッドを関数ポインタに代入することは出来るのですが、
(2)のようにクラスのメンバメソッドとして定義したメソッドは関数ポインタに代入することは出来ませんでした。
Error:バインドされた関数へのポインターは関数の呼び出しにのみ使用できます。
というエラーが発生します。
関数ポインタに外部参照でメソッドを代入することは出来ないのでしょうか?
-----(1)------------------------------------------------------------------
#include "stdafx.h"
#include <iostream>
using namespace std;
int f(int a, int b){
return a * b;
}
int _tmain(int argc, _TCHAR* argv[])
{
typedef int (* FUNC_POINTER)(int, int);
FUNC_POINTER fp;
fp = f;
cout << fp(1,2) <<endl;
getchar();
return 0;
}
-------------------------------------------------------------------------
-----(2)------------------------------------------------------------------
#include "stdafx.h"
#include <iostream>
using namespace std;
class MPointerList{
public:
int f(int a, int b){
return a * b;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
typedef int (* FUNC_POINTER)(int, int);
FUNC_POINTER fp;
//fp = f;
MPointerList mP;
fp = mP.f;
cout << fp(1,2) <<endl;
getchar();
return 0;
}
-------------------------------------------------------------------------
No.2ベストアンサー
- 回答日時:
(1) インスタンスメンバ関数は代入できない
既に回答がありますが、インスタンスメンバ関数のポインタは int (MPointerList::*)(int,int) という型であり、静的な関数のポインタ int (*)(int,int) とは異なる型です。そもそも、インスタンスメンバ関数を呼び出す時は引数 a, b だけでなく持ち主のオブジェクトインスタンス mP も必要なのです。その時の呼び出し方が、(mP.*memberFunctionPointer)(a,b) になる訳です。
(2) 静的メンバ関数は代入できる
因みに、インスタンスメンバ関数ではなく、静的メンバ関数のポインタは通常の関数ポインタと同じ型です。
呼出にオブジェクトインスタンスを必要としないためです。
--------------------
class MPointerList{
public:
static int f(int a, int b){
return a * b;
}
};
FUNC_POINTER fp = &MPointerList::f; // OK
--------------------
(3) オブジェクトインスタンスと一緒に取り扱う
「メソッド」と書いている辺り、C# のデリゲートや Delphi のメソッドポインタの様な使い方を期待していますか? (C++ ではメンバ関数の事をメソッドとは言わないので…。)
実は、デリゲートやメソッドポインタは、内部的には単なる関数ポインタではなく (オブジェクトインスタンスへの参照) と (メンバ関数へのポインタ) のペアです。C++ でも同様の事をしたければ、同じようにインスタンスへの参照とメンバ関数へのポインタのペアを取り扱う関数オブジェクトのクラスを用意すれば良いのです。
そして、C++11 でその様なクラスが標準ライブラリに追加されました。std::function です。Visual Studio 2010 以降など C++11 に (部分的に) 対応している最近のコンパイラで使えます (もちろん、古いコンパイラではコンパイルできないコードになってしまうという問題はありますが)。更に、C++11 のラムダ式と組み合わせればその様な関数オブジェクトの生成も簡単になります。
--------------------
#include <functional>
using namespace std;
int globalFunction(int a, int b){
return a * b;
}
class MPointerList{
public:
static int staticMemberFunction(int a, int b){
return a * b;
}
int instanceMemberFunction(int a, int b){
return a * b;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
std::function<int(int,int)> fp;
// もちろん、静的な関数は代入できる
fp = globalFunction;
// 静的なメンバ関数も代入できる
fp = &MPointerList::staticMemberFunction;
MPointerList mP;
// &MPointerList::f と mP への参照から関数オブジェクトを生成し、fp に代入できる
fp = std::bind(std::mem_fn(&MPointerList::instanceMemberFunction), std::ref(mP), std::placeholders::_1, std::placeholders::_2);
// ラムダ式を使えば、上と同等の事をより簡単に書ける。
fp = [&mP](int _1,int _2) -> int{return mP.instanceMemberFunction(_1,_2);};
cout << fp(1,2) <<endl;
getchar();
return 0;
}
--------------------
★注意★
mP の寿命に注意して下さい。変数 mP の寿命が尽きた後も、fp の中に mP への参照が残りますが、この時に fp を呼び出すと異常動作します。変数 mP のスコープの外で fp を使いたい場合には、MPointerList を動的に確保して寿命を管理する必要があります。その為には、C++11 の std::shared_ptr (~寿命自動管理機能付きポインタ) を使うと楽です。
--------------------
#include <memory>
中略
std::shared_ptr<MPointerList> mP2=std::make_shared<MPointerList>();
fp = [mP2](int _1,int _2)->int{return mP2->instanceMemberFunction(_1,_2);};
//※参照キャプチャ [&mP2] ではなく値キャプチャ [mP2]
--------------------
akinomyogaさん
とても詳しいご説明
大変有難うございました。
C++は本当に様々なことができるのですね。
自分も精進しようと思います。
No.1
- 回答日時:
> 関数ポインタに外部参照でメソッドを代入することは出来ないのでしょうか?
できません。
やるならこんな↓カンジ。
#include <iostream>
using namespace std;
class MPointerList{
public:
int f(int a, int b){
return a * b;
}
};
int main()
{
typedef int (MPointerList::* FUNC_POINTER)(int, int);
FUNC_POINTER fp;
fp = &MPointerList::f;
MPointerList mP;
cout << (mP.*fp)(1,2) <<endl;
getchar();
return 0;
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
適切な変換関数が存在しない???
C言語・C++・C#
-
既定のコンストラクタがない?
C言語・C++・C#
-
既定のコンストラクタがありません。というエラーについて
C言語・C++・C#
-
-
4
静的でないメンバ関数の呼び出しが正しくありません
C言語・C++・C#
-
5
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
6
変数名の付け方
Java
-
7
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
8
エラーの原因は?「この関数の定義が見つかりません」
C言語・C++・C#
-
9
文字列の切り出し
C言語・C++・C#
-
10
char*を初期化したいのですが
C言語・C++・C#
-
11
C言語で、メモリを解放しないで終わるプログラム
C言語・C++・C#
-
12
構造体のメンバをfor文で回したい
C言語・C++・C#
-
13
C++ で、「)」が必要 というエラー
C言語・C++・C#
-
14
戻り値で構造体を返すことは可能でしょうか?
C言語・C++・C#
-
15
DLLでLIBファイルが作成されない
C言語・C++・C#
-
16
構造体のextern方法
C言語・C++・C#
-
17
deleteで開放するとエラーになる原因がわからない
C言語・C++・C#
-
18
std::stringからLPCWSTR型への変換
C言語・C++・C#
-
19
VC++ 2008 EXPRESS _T"識別子がみつかりません"
C言語・C++・C#
-
20
クラスのアドレスを引数として渡したい
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語での引数の省略方法
-
「指定されたキャストは有効で...
-
複数桁10進数の*桁目だけを抽出...
-
#define _CRT_SECURE_NO_WARNIN...
-
if と配列の組み合わせ
-
式は定数値が必要です」という...
-
ラップ関数とはどんなものですか?
-
【C++】関数ポインタの使い方
-
C言語 エラーの原因がわからな...
-
C言語初心者です、、、お助けく...
-
整数データの配列から同じ値の...
-
数字列を3桁ごとにカンマで区切...
-
struct tanka_kosuu kosuu[10];...
-
エラー 添字が付けられた値が、...
-
iTRONプログラミング
-
PowerShellがうまくいかない
-
毎回違う乱数を生成するにはど...
-
入力を待たずにstdinの監視をし...
-
C言語 逆順の配列の仕方を教え...
-
C++でvectorにテキストファイル...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
複数桁10進数の*桁目だけを抽出...
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
#define _CRT_SECURE_NO_WARNIN...
-
C言語 エラーの原因がわからな...
-
ラップ関数とはどんなものですか?
-
【C++】関数ポインタの使い方
-
if と配列の組み合わせ
-
(int *)の意味
-
ColorをRGBで指定する方法
-
未解決の外部シンボル _printf...
-
構造体の勉強中です 合計点の高...
-
商と剰余を同時に求める(C言語)
-
C言語で分からないところがあり...
-
式は定数値が必要です」という...
-
C言語での奇数の和
-
std::set<int> で、ある値が何...
-
課題でつまってます・・・
-
int16_t の _t は何?
-
比較回数と交換回数表示について
おすすめ情報