
関数ポインタの使い方で悩んでいます。
下記の
(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も見ています
-
プロが教える店舗&オフィスのセキュリティ対策術
中・小規模の店舗やオフィスのセキュリティセキュリティ対策について、プロにどう対策すべきか 何を注意すべきかを教えていただきました!
-
<unistd.h>をVisualStudioでつかえるようにする
C言語・C++・C#
-
既定のコンストラクタがない?
C言語・C++・C#
-
c++,ある関数のクラスから別のクラスの関数を呼ぶ
C言語・C++・C#
-
-
4
適切な変換関数が存在しない???
C言語・C++・C#
-
5
VC++から引数付きexeファイルの実行
C言語・C++・C#
-
6
char*を初期化したいのですが
C言語・C++・C#
-
7
C++のfor文について
C言語・C++・C#
-
8
C++にてtemplateで受け取った任意の型の変数が何型であるかを判定したい
C言語・C++・C#
-
9
関数から配列を返すには?
C言語・C++・C#
-
10
1 つ以上の複数回定義されているシンボルが見つかりました
C言語・C++・C#
-
11
unsigned long long 型のフォーマット指定子
C言語・C++・C#
-
12
1 つのヘッダファイルに複数のクラスって?
C言語・C++・C#
-
13
std::stringからLPCWSTR型への変換
C言語・C++・C#
-
14
init関数の意味
C言語・C++・C#
-
15
C言語 配列の長さの上限
C言語・C++・C#
-
16
既定のコンストラクタがありません。というエラーについて
C言語・C++・C#
-
17
VC++ 2008 EXPRESS _T"識別子がみつかりません"
C言語・C++・C#
-
18
クラスのアドレスを引数として渡したい
C言語・C++・C#
-
19
error C3867 関数呼び出しには引数リスト
C言語・C++・C#
-
20
角度からベクトルに変換するにはどうしたら良いでしょうか。例えばX方向にx°、Y方向にy°、Z方向にz
計算機科学
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語での引数の省略方法
-
複数桁10進数の*桁目だけを抽出...
-
(マルチスレッド)_beginthrea...
-
「指定されたキャストは有効で...
-
if と配列の組み合わせ
-
ラップ関数とはどんなものですか?
-
#define _CRT_SECURE_NO_WARNIN...
-
C言語 エラーの原因がわからな...
-
任意の文字列のアルファベット...
-
return 1L
-
【C++】関数ポインタの使い方
-
式は定数値が必要です」という...
-
read関数をノンブロッキングで...
-
実数の整数部,小数部の取得
-
C言語での奇数の和
-
C言語で分からないところがあり...
-
double型の値を、一桁ずつint型...
-
DLLをGetProcAddress()で実行で...
-
課題でつまってます・・・
-
ColorをRGBで指定する方法
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
複数桁10進数の*桁目だけを抽出...
-
#define _CRT_SECURE_NO_WARNIN...
-
C言語 エラーの原因がわからな...
-
【C++】関数ポインタの使い方
-
if と配列の組み合わせ
-
変数名を引数として渡す、アド...
-
ラップ関数とはどんなものですか?
-
数字列を3桁ごとにカンマで区切...
-
実数の整数部,小数部の取得
-
因数分解を行うプログラムについて
-
(int *)の意味
-
C言語での奇数の和
-
system関数がうまくいかない
-
c言語の配列を使ってサイコロを...
-
シグマ公式・・・C言語
-
read関数をノンブロッキングで...
-
構造体の勉強中です 合計点の高...
-
式は定数値が必要です」という...
おすすめ情報