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

Pointer to member function C++

我是 C++ 的新手,我在使用指向成员函数的指针函数时遇到问题。我正在 ESP8266 上使用 PlatformIO 编程。

UdpTask.h

class UdpTask : public Task {
  public:
    void setup();
    void loop();
    UdpTask(String (*handleGson)(String));
  private:
    char replyPacket[];
    char incomingPacket[UDP_TX_PACKET_MAX_SIZE];
    unsigned int localUdpPort;
    WiFiUDP Udp;
    String (*handleGson)(String);
};

UdpTask.cpp

UdpTask::UdpTask(String(*handleGson)(String)) {
  this->handleGson = handleGson; 
}

GsonHandler.h

class GsonHandler {
  public:
    String handleGson(String gson);
}; 

GsonHandler.cpp

String GsonHandler::handleGson(String gson) {
  return ":)";
}

main.cpp

GsonHandler gsonHandler;
UdpTask udpTask(&gsonHandler.handleGson);

错误:

src\main.cpp:16:30: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&GsonHandler::handleGson' [-fpermissive]
 UdpTask udpTask(&gsonHandler.handleGson);
                              ^
src\main.cpp:16:40: error: no matching function for call to 'UdpTask::UdpTask(String (GsonHandler::*)(String))'
 UdpTask udpTask(&gsonHandler.handleGson);

注: 我已经尝试了错误消息中的建议,但我找不到让它工作的方法......此外,我知道在这个简单的例子中它可以更容易地解决,例如只传递整个对象,但我再次需要这种指针,因为这种方式更容易。

提前致谢。

As it was pointed out already in the comments - the argument that UdpTask(String (*handleGson)(String)); constructor expects is not a pointer to a member function. Rather it is a pointer to a free function. A pointer to a member function would be of the form:

String (GsonHandler::*)(String) 

Note that pointer to a member need to know a member of what type it is.

As to your original problem - there are a number of ways to solve it (as always the case with C++).

Most straightforward is to use std::function<String(String)> to store a functor. That is any object that can be called. So something like:

class UdpTask : public Task {
  public:
    UdpTask(std::function<String(String)> f);
  private:
...
std::function<String(String)> handler;
};

In the implementation, you just call it as: handler(args);

In case you can not use std function - other solutions can be explored.

Simplest would be to store a pointer to a handler in you UdpTask and call its method directly:

class UdpTask : public Task {
  public:
    UdpTask(GsonHandler* handler);
  private:
...
GsonHandler* handler;
};

In the implementation, you just call it as: handler->handleGson(args);

Now, I do recognise that there might be arcitual concerns about tight coupling between UdpTask and what is eccentially a UDP data handler. So you may consideg making generic interface for DataHandler, storing pointer to it and making GsonHandler an implementation of DataHandler:

struct DataHandler {
virtual ~DataHandler() = default;
virtual String handleData(String data) = 0;
}; 

struct GsonHandler: public DataHandler {
 String handleData(String data) override;
...
};
...


class UdpTask : public Task {
  public:
    UdpTask(DataHandler* handler);
  private:
...
DataHandler* handler;
};