Как передать указатель на метод экземпляра класса, как параметр конструктора?

Тема в разделе "LANGS.C", создана пользователем drem1lin, 11 апр 2017.

Метки:
  1. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Добрый вечер, подскажите.
    Я написал класс чтения из pipe и заметил, что сообщения дробятся, по этому я решил создать класс буферизатора, который будет накапливать прочтенные данные. Класс, читающий данные из pipe, в своем конструкторе имеет параметр, указывающий, какую функцию надо вызвать, когда приходят данные и туда я хочу передать функцию из класса буферизатора. Напрямую это сделать нельзя, так как функция экземпляра не является static. Я начал читать про путь с использованием подставного callback, но потом наткнулся, что можно использовать std::function и std::bind. Вот это я и попытался сделать, но так и не понял, как довести дело до ума.
    В классе, который читает данные из pipe я определил
    Код (Text):
    1. class NamedPipeClass
    2. {
    3.         NamedPipeClass(char* _pipeName, bool isClient, std::function<void(unsigned char*, unsigned int)> ReadCallBack)
    4.         {
    5.            ....
    6.           onReadCallback = ReadCallBack;
    7.         };
    8.   std::function<void(unsigned char*, unsigned int)> onReadCallback;
    9. }
    И создавая экземпляр класса
    Код (Text):
    1. MessageCollectorClass* msgCollector = new MessageCollectorClass();
    2.   NamedPipeClass* hltPipe = new NamedPipeClass(myfifo, true, std::bind(&msgCollector::AddData, this, std::placeholders_1));
    но это не правильно. Подскажите, как это сделать корректно?
     
  2. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Если уж взялся за ООП, то передавай объекты, а не функции.
    Создаем чисто абстрактный класс:
    Код (C):
    1.  
    2. class IPipeEventHandler
    3. {
    4. public:
    5.     virtual void OnDataReceived (LPVOID data, DWORD size) = 0;
    6. };
    7.  
    Далее создаем наш класс-буфер:
    Код (C):
    1.  
    2. class PipeBuffer : public IPipeEventHandler
    3. {
    4. public:
    5.     void OnDataReceived (LPVOID data, DWORD size);
    6.    
    7. private:
    8.     LPVOID m_data;
    9.     DWORD m_dataSize;
    10. };
    11. void PipeBuffer::OnDataReceived (LPVOID data, DWORD size)
    12. {
    13.     LPVOID dataEnd;
    14.    
    15.     if (!m_data)
    16.     {
    17.         m_data = malloc (size);
    18.         dataEnd = m_data;
    19.         m_dataSize = 0;
    20.     }
    21.     else
    22.     {
    23.         m_data = realloc (m_data, m_dataSize + size);
    24.         dataEnd = (LPBYTE)m_data + m_dataSize;
    25.     }
    26.    
    27.     memcpy (dataEnd, data, size);
    28.     m_dataSize += size;
    29.     /* Если данные в буфере полностью собраны, обрабатываем их и особождаем буфер */    
    30. }
    31.  
    Конструктор класса NamedPipe получает указатель на абстрактный IPipeEventHandler, метод OnDataReceived() которого он будет вызывать при чтении из пайпа каждого фрагмента данных.
    При создании класса NamedPipe, мы передаем ему указтель на созданый ранее объект класса PipeBuffer:
    Код (C):
    1.  
    2. class NamedPipe
    3. {
    4. public:
    5.     NamedPipe (IPipeEventHandler* eventHandler)
    6.     {
    7.         m_eventHandler = eventHandler;
    8.     }
    9.    
    10. private:
    11.     IPipeEventHandler* m_eventHandler;
    12.     /*
    13.         void NamedPipe::ReadPipe ()
    14.         {
    15.             ...
    16.             ReadFile (m_pipeHandle, buffer, maxSize, &bytesRead, NULL);
    17.             m_eventHandler->OnDataReceived (buffer, bytesRead);
    18.             ...
    19.         }
    20.     */
    21. };
    22. PipeBuffer* pipeBuffer = new PipeBuffer;
    23. NamedPipe* pipe = new NamedPipe (pipeBuffer);
    24.  
     
  3. Ronin_

    Ronin_ Active Member

    Публикаций:
    1
    Регистрация:
    24 дек 2016
    Сообщения:
    252
    rmn, не твори сущностей без нужды... Ога, ога.

    Код (C++):
    1. class PipeBuffer : public IPipeEventHandler
    2. {
    3. public:
    4.     void OnDataReceived (LPVOID data, DWORD size);
    5.  
    6. private:
    7.     LPVOID m_data;
    8.     DWORD m_dataSize;
    9. };
    private спецификатор доступа по умолчанию, не?

    И зачем в вашем листинге тогда комментарии?
     
  4. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Но тогда private-данные придется описывать в начале определения класса, что ухудшит воспринимаемость кода, так как в первую очередь в определении класса нас интересует его public-интерфейс.

    Комментарии там затем, что выполняют роль заглушки, на месте которой необходимо разместить код, реализующий задачу, указанную в комментариях.

    Постарайся получше, у меня тут еще много сообщений (есть и с кривым кодом) :)
     
  5. Ronin_

    Ronin_ Active Member

    Публикаций:
    1
    Регистрация:
    24 дек 2016
    Сообщения:
    252
    Профессиональные программисты так не пишут, это плохой код, так пишут дилетанты, если вам хотелось вынести в начало public, то для этого есть Сишные структуры которые умеют работать не только как POD структуры, но и как классы. Там public юзается по умолчанию, следовательно вы бы добились вынести публичные данные в начало, при этом специкатор доступа у вас юзался бы ровно один раз.
    И хороший стиль в классах это сначала private, protected, public, в независимости что вы там хотели обозначить.

    Он там не нужен, более того избыточен. Для этого есть TODO.
     
  6. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Ты скозал? А приведи-ка нам пруфца из какого-нибудь профессионального и авторитетного кодеса? :)
     
  7. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Если бы это был рабочий код, то да. А в псевдокоде-примере можно обойтись и комментарием.
     
  8. Ronin_

    Ronin_ Active Member

    Публикаций:
    1
    Регистрация:
    24 дек 2016
    Сообщения:
    252
    lol detected, герберта шилдта почитайте, которого сегодня уже упоминал и который принимал стандарт ANSI/ISO 98, guthub, etc.

    Какой ещё псевдокод? Вы давали ответ своим листингом как рабочим вариантом.
     
  9. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Ой, все :)