C ++ - calling a derived function from an abstract base pointer

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?

+4
source share
4 answers

I'm not sure if this is the problem you see, but certainly the problem is in the following function.

 void Shutdown() { MASON::UINT16 i; for(i=0;i<this->servers.size();i++) { this->Shutdown((*this->servers.begin()).first); } } 

After each iterator of the loop, i will increase by one AND size , decrease, so that you leave only half of your servers. Perhaps the preservation of some discoveries is the cause of further errors.

You can do the following:

 void Shutdown() { MASON::UINT16 i; std::size_t nrServers = this->servers.size(); for(i=0;i<nrServers;i++) { this->Shutdown((*this->servers.begin()).first); } } 

or, which I would prefer, as it better shows the intention of the code:

 void Shutdown() { while (!this->servers.empty()) { this->Shutdown((*this->servers.begin()).first); } } 
0
source

Check the syntax of what you declare:

 class TCPDaemon { virtual void stop() = 0; }; class MyDaemon : public TCPDaemon { virtual void stop() { //Do stuff here. } }; 

This is the best I can do without code.

EDIT:

Well, it looks like you are using abstract functions. The next question is: what error do you get? I can confidently say that I am not trying to call Stop () from TCPDeamon. This would be impossible, since it is not even implemented.

+1
source

In the end, I finally worked out thanks to what I got. The problem was calling delete in TCPServer :: Shutdown (unsigned short), which caused a memory access violation in a completely different part of the code ... Rather, noobie error, I will spoof smart pointers around everything as soon as possible.

Thanks for all your feedback!

+1
source

If you say that it calls a pure virtual method instead of a version of a derived class, it means that your derived class calls it. For instance.

 class t1 { public: virtual ~t1(){}; virtual void foo()=0 { std::cout << "pure virtual"; }; }; class t2:public t1 { public : virtual void foo() { t1::foo(); std::cout << "derived class "; }; }; 

As far as I remember, only a pure virtual function of the class "object can call the base class" (of course, if it is implemented in the base class)

0
source

All Articles