Указатель на функцию-член C ++ - PullRequest
0 голосов
/ 03 февраля 2020

Я новичок в C ++, и у меня проблемы с указателями на функции-члены. Я программирую с PlatformIO на ESP8266.

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

Примечание: Я попробовал предложения в сообщении об ошибке, но не могу не могу найти способ заставить его работать ... кроме того, я знаю, что в этом простом примере это можно решить гораздо проще, например, просто пропустив весь объект, но мне снова нужны такие указатели, где этот путь проще .

Заранее спасибо.

1 Ответ

1 голос
/ 03 февраля 2020

Как уже указывалось в комментариях - аргумент, который ожидает конструктор UdpTask(String (*handleGson)(String));, не является указателем на функцию-член. Скорее это указатель на функцию free . Указатель на функцию-член будет иметь вид:

String (GsonHandler::*)(String) 

Обратите внимание, что указатель на член должен знать член его типа.

Что касается вашей первоначальной проблемы - существует несколько способов ее решения (как всегда в случае с C ++).

Наиболее простым является использование std::function<String(String)> для хранения functor. Это любой объект, который можно назвать. Так что-то вроде:

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

В реализации вы просто называете это как: handler(args);

В случае, если вы не можете использовать функцию std - другое решения могут быть изучены.

Простейшим будет сохранить указатель на обработчик в вас UdpTask и вызвать его метод напрямую:

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

В реализации вы просто вызываете его как : handler->handleGson(args);

Теперь я признаю, что могут существовать некоторые опасения насчет жесткой связи между UdpTask и тем, что является экстенционально UDP data handler. Поэтому вы можете подумать о создании универсального c интерфейса для DataHandler, сохранении указателя на него и создании GsonHandler реализации 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;
};

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...