簡體   English   中英

C ++-從抽象基本指針調用派生函數

[英]C++ - calling derived function from abstract base pointer

我一直在嘗試基於繼承創建TCP Server模型,但取得了不同的成功。 這些服務器由單例服務器管理,其任務是關閉這些服務器以及其他簡單的維護功能:

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;

};

TCPDaemon類的Stop()函數是純虛擬的。 我的問題是,在調用Shutdown()函數時,它試圖調用此純虛函數而不是派生類的版本。 我如何強迫它做正確的事?

提前致謝

[edit]抱歉,我之前沒有包含TCPDaemon代碼,它是從TCPSocket類派生的(我已經檢查過它是100%工作的,並且是不言自明的)。 這里是:

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;

};

這是派生服務器及其創建方法的示例:

   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]我認為問題可以歸結為:(我很容易錯了):我有一個基本類TCPDaemon的std :: map,它具有純虛擬/抽象函數Stop()。 似乎當我通過映射中的一項調用Stop()時,它試圖調用TCPDaemon :: Stop(),而不是重寫函數EchoServer :: Stop()。 這可能是問題嗎? 如果是這樣,我該如何解決?

檢查您聲明的語法:

class TCPDaemon
{
    virtual void stop() = 0;
};

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

如果沒有更多代碼,那是我能做的最好的事情。

編輯:

好的,看來您正在使用抽象函數。 下一個問題是:您遇到的錯誤是什么? 我可以肯定地說,它不是試圖從TCPDeamon調用Stop()。 這將是不可能的,因為甚至沒有實施。

最終,由於收到了我的意見,我終於完成了工作。 問題出在TCPServer :: Shutdown(unsigned short)中的delete調用,這在代碼的完全不同的部分中導致了內存訪問沖突……一個相當不合理的錯誤,我將盡快將智能指針包裝在所有內容周圍。

感謝您的所有反饋!

如果您說它調用純虛擬方法而不是派生類的版本,則意味着您的派生類將其調用。 例如

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

據我所記得,只有派生類的對象可以調用基類的純虛函數(當然,如果它是在基類中實現的)

我不確定這是否是您遇到的問題,但是以下函數肯定存在問題。

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

在每個循環迭代器之后, i將增加一個,而size將減少,因此您將僅關閉一半的服務器。 也許保持開放是進一步錯誤的原因。

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

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

或者,我希望它更好地顯示了代碼的意圖:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM