プロが教える店舗&オフィスのセキュリティ対策術

関数ポインタの使い方で悩んでいます。
下記の
(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;
}
-------------------------------------------------------------------------

A 回答 (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]
--------------------
    • good
    • 0
この回答へのお礼

akinomyogaさん
とても詳しいご説明
大変有難うございました。

C++は本当に様々なことができるのですね。
自分も精進しようと思います。

お礼日時:2014/07/12 03:59

> 関数ポインタに外部参照でメソッドを代入することは出来ないのでしょうか?



できません。
やるならこんな↓カンジ。

#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;
}
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A