C ++ - 从抽象基指针调用派生的函数 [英] C++ - calling derived function from abstract base pointer

查看:128
本文介绍了C ++ - 从抽象基指针调用派生的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在试图创建一个基于继承的TCP服务器模型,并取得了不同的成功。这些服务器由单独管理,它的任务是关闭这些服务器和其他简单的维护功能:

  class TCPServer {
public:
TCPServer();
〜TCPServer();

void Bind(TCPDaemon * daemon){
if(!daemon-> IsRunning()){
throw TCPBindException(Daemon is inactive);
}

//如果不使用端口,则将此守护程序绑定到
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 servers.size(); i ++){
this-> Shutdown((* this-> servers.begin())。 ;
}
}

无关闭(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 *>服务器;

};

TCPDaemon类的Stop()函数是一个纯虚函数。我的问题是,当Shutdown()函数被调用时,它试图调用这个纯虚拟而不是派生类的版本。如何强制它做正确的事?



提前感谢



不包括之前的TCPDaemon代码,它来自一个TCPSocket类(我已经检查是100%工作,是相当不言自明的)。这是:

 类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(无法启动WSA);
}
#endif

this-> raw_socket = socket(AF_INET,SOCK_STREAM,0);
if(this-> raw_socket< = 0){
throw TCPDaemonException(无法创建套接字);
}

if(int status = bind(this-> raw_socket,(sockaddr *)& opts,sizeof(sockaddr))){
printf(error [ %i] \r\\\
,status);
throw TCPDaemonException(无法绑定到端口);
}

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客户端;
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;

};

这里是一个示例派生服务器及其创建方法:



class EchoServer:public TCPDaemon {
public:
EchoServer(MASON :: UINT16 port):TCPDaemon(port){
}

〜EchoServer(){}

virtual void Start(){

}

virtual void Run TCPSocket * client){
printf(RUN\r\\\
);
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]我想问题归结为这是):
我有一个基类的std :: map,TCPDaemon,它有一个纯虚拟/抽象函数Stop()。看起来当我通过地图中的一个条目调用Stop()时,它试图调用TCPDaemon :: Stop(),而不是覆盖函数EchoServer :: Stop()。这是问题吗?

解决方案

我不确定这是否是您遇到的问题,在下面的函数中肯定有一个问题。

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

在每个循环迭代器之后, i 会增加一个,而 size 会减少,所以你只需要ShutDown一半的服务器。



您可以执行以下任一操作:

 

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

或者,我更喜欢,因为它更好地显示代码的意图:

  void Shutdown(){
while(!this-> servers.empty ){
this-> Shutdown((* this-> servers.begin())。
}
}


I have been trying to create a TCP Server model based on inheritance, with varying success. These servers are managed by a singleton whose task it is to shut these servers down 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 TCPDaemon class's Stop() function is a pure virtual. My problem is that when the Shutdown() function is called, it is attempting to call this pure virtual instead of the derived class' version. How can I force it to do the right thing?

Thanks in advance

[edit] sorry I did not include the TCPDaemon code before, it derives from a TCPSocket class (which I have checked to be 100% working and is fairly self-explanatory). Here it 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 a sample derived server and its method of creation:

   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 what the problem boils down to is this (i could easily be wrong): I have a std::map of the base class, TCPDaemon, which has a pure virtual/abstract function Stop(). It appears that when I call Stop() through one of the entries in the map, it is attempting to call TCPDaemon::Stop(), as opposed to the overriding function EchoServer::Stop(). Could this be the issue? If so, how do I resolve it?

解决方案

I'm not sure if this is the problem you're seeing, but there's certainly a problem 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 loop iterator, i will increase by one AND size will decrease, so you'll only ShutDown half your servers. Maybe keeping some open is the cause of further errors.

You could do either:

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

这篇关于C ++ - 从抽象基指针调用派生的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆