C++ C++;-从抽象基指针调用派生函数

C++ C++;-从抽象基指针调用派生函数,c++,inheritance,pure-virtual,C++,Inheritance,Pure Virtual,我一直在尝试创建一个基于继承的TCP服务器模型,并取得了不同的成功。这些服务器由单机管理,单机的任务是关闭这些服务器和其他简单的维护功能: class TCPServer { public: TCPServer(); ~TCPServer(); void Bind(TCPDaemon *daemon) { if(!daemon->IsRunning()) { throw TCPBindException("Daemon is

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

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;

};
类TCPServer{
公众:
TCPServer();
~TCPServer();
无效绑定(TCPDaemon*守护进程){
如果(!daemon->IsRunning()){
抛出TCPBindException(“守护进程处于非活动状态”);
}
//如果端口未被占用,请将此守护程序绑定到该端口
if(this->servers.count(守护进程->端口())==0){
此->服务器[守护进程->端口()]=守护进程;
...
}否则{
抛出TCPBindException(“端口被占用”);
}
}
无效关机(){
梅森:UINT16 i;
对于(i=0;iservers.size();i++){
此->关机((*此->servers.begin()).first);
}
}
无效关机(无符号短端口){
如果(此->服务器计数(端口)){
如果(此->服务器[端口]->IsRunning()){
此->服务器[端口]->停止();
}
删除此->服务器[端口];
此->服务器。擦除(端口);
}
}
私人:
地图服务器;
};
TCPDaemon类的Stop()函数是纯虚拟函数。我的问题是,当调用Shutdown()函数时,它试图调用这个纯虚拟类,而不是派生类的版本。我怎样才能强迫它做正确的事情

提前谢谢

[编辑]很抱歉,我之前没有包含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;

};
TCPDaemon类:公共TCPSocket{
公众:
TCPDaemon(无符号短端口){
此->\u enabled=false;
此->\u host.ipaddr(INADDR\u ANY);
此->\u主机端口(端口);
此->暂停=错误;
opts中的struct sockaddr_=this->_host.Compile();
#ifdef平台\u窗口
WSADATA WSADATA;
if(WSAStartup(0x0202和wsaData)){
抛出TCPDaemonException(“启动WSA失败”);
}
#恩迪夫
此->原始套接字=套接字(AF\u INET,SOCK\u STREAM,0);
if(此->原始套接字(sockaddr*)和opts,sizeof(sockaddr))){
printf(“错误[%i]\r\n”,状态);
抛出TCPDaemonException(“绑定到端口失败”);
}
如果(听(这个->原始插槽,5)){
抛出TCPDaemonException(“在端口上侦听失败”);
}
此->\u enabled=true;
}
虚拟~TCPDaemon(){
此->关机();
}
虚拟void Start()=0;
虚拟无效运行(TCPSocket*)=0;
虚空停止()=0;
无符号短端口(){
返回此->主机().port();
}
bool IsRunning(){
返回此->\u已启用;
}
TCPSocket*Accept(){
套接字客户端;
结构sockaddr客户端\u addr;
int len=sizeof(客户地址);
client=accept(此->原始套接字和客户端地址(&len);
返回新的TCPSocket(客户端和客户端地址);
}
无效关机(){
}
私人:
bool_启用;
布尔停顿了一下;
};
下面是一个示例派生服务器及其创建方法:

   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));
class EchoServer:public TCPDaemon{
公众:
EchoServer(MASON::UINT16端口):TCPDaemon(端口){
}
~EchoServer(){}
虚拟空开始(){
}
虚拟无效运行(TCPSocket*客户端){
printf(“运行\r\n”);
访问器acc_客户端=客户端;
acc_client->Write(访问器(新的Blob(std::string(“hello!”)));
acc_客户端->断开连接();
}
虚拟无效停止(){
}
};
myTCPServer->Bind(新的EchoServer(8008));
[编辑+1]我认为问题归结为以下几点(我很容易出错):
我有一个基类TCPDaemon的std::map,它有一个纯虚拟/抽象函数Stop()。似乎当我通过映射中的一个条目调用Stop()时,它正试图调用TCPDaemon::Stop(),而不是重写函数EchoServer::Stop()。这可能是问题所在吗?如果是这样,我该如何解决它呢?

如果您说它调用纯虚拟方法而不是派生类的版本,这意味着您的派生类调用它。例如

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 ";
};
};
t1类
{
公众:
虚~t1(){};
虚拟void foo()=0
{

std::cout检查所声明内容的语法:

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

class MyDaemon : public TCPDaemon
{
    virtual void stop()
    {
        //Do stuff here.
    }
};
这是我能做的最好的没有更多的代码

编辑:


好的,看起来您使用的是抽象函数。下一个问题是:您得到的错误是什么?我可以肯定地说,它不是试图调用Stop()的这是不可能的,因为它甚至还没有实现。

我不确定这是否是您看到的问题,但下面的函数肯定有问题

void Shutdown() {
    MASON::UINT16 i;
    for(i=0;i<this->servers.size();i++) {
        this->Shutdown((*this->servers.begin()).first);
    }
}
或者,我更喜欢这一点,因为它更能体现准则的意图:

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

多亏了我收到的输入,我最终解决了这个问题。问题在于TCPServer::Shutdown(unsigned short)中的delete调用,它在代码的完全不同部分导致了内存访问冲突……这是一个相当严重的错误,我将尽快将智能指针包装到所有内容中


感谢您的反馈!

您能给我们
TCPDaemon
的失败代码,而不是调用失败代码的函数吗?我想我们需要查看TCPDaemon的相关部分以及它的一个派生类,以便对您有所帮助。TCPDaemon是基类还是派生类?显示定义s表示基和派生。我猜您调用Bind时使用了错误类的实例。例如,没有Stop()实现的类,我们可以看到更多的代码吗
void Shutdown() {
    while (!this->servers.empty()) {
        this->Shutdown((*this->servers.begin()).first);
    }
}