Re: Callback и наследование
От: Анатолий Широков СССР  
Дата: 26.10.10 13:09
Оценка: 3 (1)

struct EventListener
{
      virtual void ClientEvent(...) = 0;  
      virtual void RecvEvent(...) = 0;  
};

class Client
{
    EventListener* m_eventListener;
public:
    Client() :  m_eventListener(0) {}
    explicit Client(EventListener &eventListener) : m_eventListener(&eventListener) {}
    void eventListener(EventListener &eventListener) {m_eventListener=&eventListener;}
...
protected:
    void FireClientEvent() {if(m_eventListener)m_eventListener->ClientEvent(...);}
    void FireRecvEvent() {if(m_eventListener)m_eventListener->RecvEvent(...);}
};

class Server : public EventListener
{ 
   std::list<Client*> m_Clients;
public:
   void addClient(std::auto_ptr<Client> client) {client->eventListener(*this);m_Clients.push_back(client.release());}
};

class ServerEx : public Server
{
...
};
Callback и наследование
От: neherim Россия  
Дата: 26.10.10 12:49
Оценка:
Здравствуйте, в программировании я новичок, как решить свою проблему догадываюсь, но не уверен что это решение будет правильным и в стиле c++.

Есть класс сервера, в котором храниться список ссылок на клиентов. Когда клиент принимает информацию от устройства, эта информация должна передаваться через вызов функции HandleRecvData() в класс сервера, где и будет обработана. Адрес функции HandleRecvData(), которая сейчас является статическим методом сервера, я передаю клиенту через конструктор.

Но теперь возникла проблема, мне нужно от сервера наследовать класс, и в нем переопределить функцию HandleRecvData().
Определить ее как виртуальную — не получается, компилятор начинает грязно ругаться. вот теперь сижу и думаю, как это все грамотно "отрефакторить"

typedef void (HandleDataFunc)( const string, const char*, const int);
// класс клиента
class AMClient
{
protected:

    HandleDataFunc*  HandleRecvData;    

public:
    AMClient( SOCKET sSocket, sockaddr_in socket_addr, HandleDataFunc* HandleDataCallback )
    {
        HandleClientEvent    = HandleEventCallback;
        HandleRecvData        = HandleDataCallback;
    }
};

// класс сервера
class AMServer
{
protected:
         list<AMClient*> mClientList;

     static void  HandleRecvData( const string ClientName, const char *pData, const int Size );    
     
     AMClient* CreateClient( SOCKET sSocket, sockaddr_in socket_addr );
public:
    AMServer( const string& pIPAddrStr, unsigned short PortNumber );
    virtual ~AMServer();
};

AMClient* AMServer::CreateClient( SOCKET sSocket, sockaddr_in socket_addr )
{
    return new AMClient( sSocket, socket_addr, HandleRecvData );
}


Единственное что сейчас приходит на ум — сделать функцию CreateClient() виртуальной, и в классе наследнике переопределить ее как-то так:


class AMOpcServer : public AMServer
{
private:
    static void  HandleRecvData2( const string ClientName, const char *pData, const int Size );    

    virtual AMClient* CreateClient( SOCKET sSocket, sockaddr_in socket_addr );
};

AMClient* AMServer::CreateClient( SOCKET sSocket, sockaddr_in socket_addr )
{
    return new AMClient( sSocket, socket_addr, HandleRecvData2 );
}


Но выглядит это совсем ужасно. Ну и собственно вопрос, как сделать это все "in da c++ style"
Re: Callback и наследование
От: A.Lokotkov Россия  
Дата: 26.10.10 13:03
Оценка:
Здравствуйте, neherim, Вы писали:

N>Определить ее как виртуальную — не получается, компилятор начинает грязно ругаться. вот теперь сижу и думаю, как это все грамотно "отрефакторить"


Определить абстрактный класс (интерфейс), в котором определена чисто виртуальная функция, соответствующая коллбэку. Сервер будет реализовывать сей интерфейс и при создании клиента передавать тому this вместо адреса функции.
bloß it hudla
Re[2]: Callback и наследование
От: neherim Россия  
Дата: 26.10.10 13:40
Оценка:
Здравствуйте, A.Lokotkov, Вы писали:

AL>Определить абстрактный класс (интерфейс), в котором определена чисто виртуальная функция, соответствующая коллбэку. Сервер будет реализовывать сей интерфейс и при создании клиента передавать тому this вместо адреса функции.


то есть что-то вроде паттерна Strategy, я правильно понимаю?
Re[3]: Callback и наследование
От: A.Lokotkov Россия  
Дата: 26.10.10 13:52
Оценка:
Здравствуйте, neherim, Вы писали:

N>то есть что-то вроде паттерна Strategy, я правильно понимаю?


Не мучьте себя сопоставлением с паттернами. В ответе ниже показан вариант реализации.
bloß it hudla
Re[2]: Callback и наследование
От: Lexey Россия  
Дата: 26.10.10 16:06
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:
АШ>   void addClient(std::auto_ptr<Client> client) {client->eventListener(*this);m_Clients.push_back(client.release());}


Небольшая поправка:
m_Clients.push_back(client.get());
client.release();

Либо использовать ptr_list из буста.

И еще деструктор EventListener стоит сделать protected.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.