I am trying to create an inheritance based TCP Server model with varying degrees of success. These servers are controlled by a singleton, whose task is to close these servers and other simple maintenance functions:
class TCPServer { public: TCPServer(); ~TCPServer(); void Bind(TCPDaemon *daemon) { if(!daemon->IsRunning()) { throw TCPBindException("Daemon is inactive"); } // if the port is not taken, bind this daemon to it if(this->servers.count(daemon->port())==0) { this->servers[daemon->port()]=daemon; ... } else { throw TCPBindException("Port is taken"); } } void Shutdown() { MASON::UINT16 i; for(i=0;i<this->servers.size();i++) { this->Shutdown((*this->servers.begin()).first); } } void Shutdown(unsigned short port) { if(this->servers.count(port)) { if(this->servers[port]->IsRunning()) { this->servers[port]->Stop(); } delete this->servers[port]; this->servers.erase(port); } } private: std::map<unsigned short, TCPDaemon*> servers; };
The Stop () function of the TCPDaemon class is pure virtual. My problem is that when the Shutdown () function is called, it tries to call this pure virtual object instead of the version of the derived class. How can I make him do the right thing?
Thanks in advance
[edit] Sorry, I didn’t specify the TCPDaemon code before, it comes from the TCPSocket class (which I checked for 100% operation and quite without explanation). There he is:
class TCPDaemon: public TCPSocket { public: TCPDaemon(unsigned short port) { this->_enabled=false; this->_host.ipaddr(INADDR_ANY); this->_host.port(port); this->paused=false; struct sockaddr_in opts=this->_host.Compile(); #ifdef PLATFORM_WINDOWS WSADATA wsaData; if(WSAStartup(0x0202, &wsaData)) { throw TCPDaemonException("Failed to start WSA"); } #endif this->raw_socket=socket(AF_INET, SOCK_STREAM, 0); if(this->raw_socket<=0) { throw TCPDaemonException("Failed to create socket"); } if(int status=bind(this->raw_socket, (sockaddr*)&opts, sizeof(sockaddr))) { printf("error [%i]\r\n", status); throw TCPDaemonException("Failed to bind to port"); } if(listen(this->raw_socket, 5)) { throw TCPDaemonException("Failed to listen on port"); } this->_enabled=true; } virtual ~TCPDaemon() { this->Shutdown(); } virtual void Start()=0; virtual void Run(TCPSocket*)=0; virtual void Stop()=0; unsigned short port() { return this->host().port(); } bool IsRunning() { return this->_enabled; } TCPSocket *Accept() { SOCKET client; struct sockaddr client_addr; int len=sizeof(client_addr); client=accept(this->raw_socket, &client_addr, &len); return new TCPSocket(client, &client_addr); } void Shutdown() { } private: bool _enabled; bool paused; };
and here is an example server and its creation method:
class EchoServer: public TCPDaemon { public: EchoServer(MASON::UINT16 port): TCPDaemon(port) { } ~EchoServer() {} virtual void Start() { } virtual void Run(TCPSocket *client) { printf("RUN\r\n"); Accessor<TCPSocket> acc_client=client; acc_client->Write(Accessor<Blob> (new Blob(std::string("hello!")))); acc_client->Disconnect(); } virtual void Stop() { } }; myTCPServer->Bind(new EchoServer(8008));
[edit + 1] I think the problem comes down to this (I'm easily mistaken): I have a std :: map of the base class, TCPDaemon, which has a pure virtual / abstract Stop () function. It seems that when I call Stop () through one of the entries on the map, it tries to call TCPDaemon :: Stop (), unlike the overriding function EchoServer :: Stop (). Could this be a problem? If so, how to resolve it?