C++ 指向成员函数的函数指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2402579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:22:30  来源:igfitidea点击:

Function pointer to member function

c++oopfunction-pointers

提问by Mike

I'd like to set up a function pointer as a member of a class that is a pointer to another function in the same class. The reasons why I'm doing this are complicated.

我想将函数指针设置为类的成员,该类是指向同一类中另一个函数的指针。我这样做的原因很复杂。

In this example, I would like the output to be "1"

在这个例子中,我希望输出为“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())
}

But this fails at compiling. Why?

但这在编译时失败。为什么?

回答by Johannes Schaub - litb

The syntax is wrong. A member pointer is a different type category from a ordinary pointer. The member pointer will have to be used together with an object of its class:

语法错误。成员指针是与普通指针不同的类型类别。成员指针必须与其类的对象一起使用:

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.xdoes not yet say on what object the function is to be called on. It just says that you want to use the pointer stored in the object a. Prepending aanother time as the left operand to the .*operator will tell the compiler on what object to call the function on.

a.x尚未说明要调用该函数的对象。它只是说您要使用存储在对象中的指针a。将a另一个时间作为运算.*符的左操作数将告诉编译器在哪个对象上调用函数。

回答by Bertrand Marron

int (*x)()is not a pointer to member function. A pointer to member function is written like this: int (A::*x)(void) = &A::f;.

int (*x)()不是指向成员函数的指针。一个指针,指向成员函数是这样写的:int (A::*x)(void) = &A::f;

回答by Heto

Call member function on string command

在字符串命令上调用成员函数

#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;
}

Pay attention to (this->*func)();and the way to declare the function pointer with class name void (A::*func)()

注意(this->*func)();和用类名声明函数指针的方式void (A::*func)()

回答by Jerry Coffin

You need to use a pointer to a member function, not just a pointer to a function.

您需要使用指向成员函数的指针,而不仅仅是指向函数的指针。

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;
}

回答by Owl

While this is based on the sterling answers elsewhere on this page, I had a use case which wasn't completely solved by them; for a vector of pointers to functions do the following:

虽然这是基于本页其他地方的标准答案,但我有一个用例并没有完全被他们解决;对于指向函数的指针向量,请执行以下操作:

#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;
}

Something like this is useful if you are writing a command interpreter with indexed functions that need to be married up with parameter syntax and help tips etc. Possibly also useful in menus.

如果您正在编写一个带有索引函数的命令解释器,这些函数需要与参数语法和帮助提示等结合起来,那么这样的东西很有用。 可能在菜单中也很有用。

回答by IllidanS4 wants Monica back

While you unfortunately cannot convert an existing member function pointer to a plain function pointer, you can create an adapter function template in a fairly straightforward way that wraps a member function pointer known at compile-time in a normal function like this:

虽然遗憾的是您无法将现有成员函数指针转换为普通函数指针,但您可以以一种相当简单的方式创建一个适配器函数模板,将编译时已知的成员函数指针包装在一个普通函数中,如下所示:

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>;

Note that in order to call the member function, an instance of Amust be provided.

请注意,为了调用成员函数,A必须提供一个实例。

回答by memtha

Building on @IllidanS4 's answer, I have created a template class that allows virtually any member function with predefined arguments and class instance to be passed by reference for later calling.

以@IllidanS4 的回答为基础,我创建了一个模板类,它几乎允许任何具有预定义参数和类实例的成员函数通过引用传递以供以后调用。



template<class RET, class... RArgs> class Callback_t {
public:
    virtual RET call(RArgs&&... rargs) = 0;
    //virtual RET call() = 0;
};

template<class T, class RET, class... RArgs> class CallbackCalltimeArgs : public Callback_t<RET, RArgs...> {
public:
    T * owner;
    RET(T::*x)(RArgs...);
    RET call(RArgs&&... rargs) {
        return (*owner.*(x))(std::forward<RArgs>(rargs)...);
    };
    CallbackCalltimeArgs(T* t, RET(T::*x)(RArgs...)) : owner(t), x(x) {}
};

template<class T, class RET, class... Args> class CallbackCreattimeArgs : public Callback_t<RET> {
public:
    T* owner;
    RET(T::*x)(Args...);
    RET call() {
        return (*owner.*(x))(std::get<Args&&>(args)...);
    };
    std::tuple<Args&&...> args;
    CallbackCreattimeArgs(T* t, RET(T::*x)(Args...), Args&&... args) : owner(t), x(x),
        args(std::tuple<Args&&...>(std::forward<Args>(args)...)) {}
};

Test / example:

测试/示例:

class container {
public:
    static void printFrom(container* c) { c->print(); };
    container(int data) : data(data) {};
    ~container() {};
    void print() { printf("%d\n", data); };
    void printTo(FILE* f) { fprintf(f, "%d\n", data); };
    void printWith(int arg) { printf("%d:%d\n", data, arg); };
private:
    int data;
};

int main() {
    container c1(1), c2(20);
    CallbackCreattimeArgs<container, void> f1(&c1, &container::print);
    Callback_t<void>* fp1 = &f1;
    fp1->call();//1
    CallbackCreattimeArgs<container, void, FILE*> f2(&c2, &container::printTo, stdout);
    Callback_t<void>* fp2 = &f2;
    fp2->call();//20
    CallbackCalltimeArgs<container, void, int> f3(&c2, &container::printWith);
    Callback_t<void, int>* fp3 = &f3;
    fp3->call(15);//20:15
}

Obviously, this will only work if the given arguments and owner class are still valid. As far as readability... please forgive me.

显然,这只有在给定的参数和所有者类仍然有效时才有效。至于可读性......请原谅我。

Edit:removed unnecessary malloc by making the tuple normal storage. Added inherited type for the reference. Added option to provide all arguments at calltime instead. Now working on having both....

编辑:通过使元组正常存储删除了不必要的 malloc。添加了引用的继承类型。添加了在调用时提供所有参数的选项。现在正在努力同时拥有......

Edit 2:As promised, both. Only restriction (that I see) is that the predefined arguments must come before the runtime supplied arguments in the callback function. Thanks to @Chipster for some help with gcc compliance. This works on gcc on ubuntu and visual studio on windows.

编辑2:正如承诺的那样,两者都是。唯一的限制(我看到的)是预定义的参数必须出现在回调函数中运行时提供的参数之前。感谢@Chipster 对 gcc 合规性的一些帮助。这适用于 ubuntu 上的 gcc 和 windows 上的 Visual Studio。

#ifdef _WIN32
#define wintypename typename
#else
#define wintypename
#endif

template<class RET, class... RArgs> class Callback_t {
public:
    virtual RET call(RArgs... rargs) = 0;
    virtual ~Callback_t() = default;
};

template<class RET, class... RArgs> class CallbackFactory {
private:
    template<class T, class... CArgs> class Callback : public Callback_t<RET, RArgs...> {
    private:
        T * owner;
        RET(T::*x)(CArgs..., RArgs...);
        std::tuple<CArgs...> cargs;
        RET call(RArgs... rargs) {
            return (*owner.*(x))(std::get<CArgs>(cargs)..., rargs...);
        };
    public:
        Callback(T* t, RET(T::*x)(CArgs..., RArgs...), CArgs... pda);
        ~Callback() {};
    };
public:
    template<class U, class... CArgs> static Callback_t<RET, RArgs...>* make(U* owner, CArgs... cargs, RET(U::*func)(CArgs..., RArgs...));
};
template<class RET2, class... RArgs2> template<class T2, class... CArgs2> CallbackFactory<RET2, RArgs2...>::Callback<T2, CArgs2...>::Callback(T2* t, RET2(T2::*x)(CArgs2..., RArgs2...), CArgs2... pda) : x(x), owner(t), cargs(std::forward<CArgs2>(pda)...) {}
template<class RET, class... RArgs> template<class U, class... CArgs> Callback_t<RET, RArgs...>* CallbackFactory<RET, RArgs...>::make(U* owner, CArgs... cargs, RET(U::*func)(CArgs..., RArgs...)) {
    return new wintypename CallbackFactory<RET, RArgs...>::Callback<U, CArgs...>(owner, func, std::forward<CArgs>(cargs)...);
}