web-dev-qa-db-ja.com

メンバー関数への関数ポインター

同じクラス内の別の関数へのポインターであるクラスのメンバーとして関数ポインターを設定したいと思います。私がこれをしている理由は複雑です。

この例では、出力を「1」にしたいと思います

class A {
public:
 int f();
 int (*x)();
}

int A::f() {
 return 1;
}


int main() {
 A a;
 a.x = a.f;
 printf("%d\n",a.x())
}

しかし、これはコンパイルに失敗します。どうして?

75
Mike

構文が間違っています。メンバーポインターは、通常のポインターとは異なるタイプのカテゴリーです。メンバーポインターは、そのクラスのオブジェクトと一緒に使用する必要があります。

class A {
public:
 int f();
 int (A::*x)(); // <- declare by saying what class it is a pointer to
};

int A::f() {
 return 1;
}


int main() {
 A a;
 a.x = &A::f; // use the :: syntax
 printf("%d\n",(a.*(a.x))()); // use together with an object of its class
}

a.xは、関数がどのオブジェクトで呼び出されるかをまだ示していません。オブジェクトaに格納されているポインターを使用したいだけです。 .*演算子の左側のオペランドとしてaを先頭に追加すると、関数を呼び出すオブジェクトをコンパイラーに通知します。

131

int (*x)()は、メンバー関数へのポインターではありません。メンバー関数へのポインターは、int (A::*x)(void) = &A::f;のように記述されます。

21
Bertrand Marron

文字列コマンドでメンバー関数を呼び出す

_#include <iostream>
#include <string>


class A 
{
public: 
    void call();
private:
    void printH();
    void command(std::string a, std::string b, void (A::*func)());
};

void A::printH()
{
    std::cout<< "H\n";
}

void A::call()
{
    command("a","a", &A::printH);
}

void A::command(std::string a, std::string b, void (A::*func)())
{
    if(a == b)
    {
        (this->*func)();
    }
}

int main()
{
    A a;
    a.call();
    return 0;
}
_

_(this->*func)();_およびクラス名void (A::*func)()を使用して関数ポインターを宣言する方法に注意してください

13
Heto

関数へのポインターだけでなく、メンバー関数へのポインターを使用する必要があります。

class A { 
    int f() { return 1; }
public:
    int (A::*x)();

    A() : x(&A::f) {}
};

int main() { 
   A a;
   std::cout << (a.*a.x)();
   return 0;
}
9
Jerry Coffin

これは、このページの他の場所での最高の回答に基づいていますが、完全に解決されていないユースケースがありました。関数へのポインタのベクトルについては、次のことを行います。

#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>

class A{
public:
  typedef vector<int> (A::*AFunc)(int I1,int I2);
  vector<AFunc> FuncList;
  inline int Subtract(int I1,int I2){return I1-I2;};
  inline int Add(int I1,int I2){return I1+I2;};
  ...
  void Populate();
  void ExecuteAll();
};

void A::Populate(){
    FuncList.Push_back(&A::Subtract);
    FuncList.Push_back(&A::Add);
    ...
}

void A::ExecuteAll(){
  int In1=1,In2=2,Out=0;
  for(size_t FuncId=0;FuncId<FuncList.size();FuncId++){
    Out=(this->*FuncList[FuncId])(In1,In2);
    printf("Function %ld output %d\n",FuncId,Out);
  }
}

int main(){
  A Demo;
  Demo.Populate();
  Demo.ExecuteAll();
  return 0;
}

パラメータシンタックスやヘルプヒントなどと組み合わせる必要のあるインデックス付き関数を使用してコマンドインタープリターを作成している場合、このようなものが役立ちます。メニューでも役立つ可能性があります。

3
Owl

残念ながら既存のメンバー関数ポインターをプレーンな関数ポインターに変換することはできませんが、次のような通常の関数でコンパイル時に既知のメンバー関数ポインターをラップするかなり簡単な方法でアダプター関数テンプレートを作成できます。

template <class Type>
struct member_function;

template <class Type, class Ret, class... Args>
struct member_function<Ret(Type::*)(Args...)>
{
    template <Ret(Type::*Func)(Args...)>
    static Ret adapter(Type &obj, Args&&... args)
    {
        return (obj.*Func)(std::forward<Args>(args)...);
    }
};

template <class Type, class Ret, class... Args>
struct member_function<Ret(Type::*)(Args...) const>
{
    template <Ret(Type::*Func)(Args...) const>
    static Ret adapter(const Type &obj, Args&&... args)
    {
        return (obj.*Func)(std::forward<Args>(args)...);
    }
};

int (*func)(A&) = &member_function<decltype(&A::f)>::adapter<&A::f>;

メンバー関数を呼び出すには、Aのインスタンスを提供する必要があることに注意してください。

0
IllidanS4