2016-06-09 5 views
0

я в настоящее время работает над HttpServer и следующая проблема:C++ отливать указатель член производного класса указателю базового класса

Я хочу, чтобы зарегистрировать свои контроллеры и когда я получаю запрос я хочу, чтобы проверить, если один этих контроллеров имеет обработчик запрошенного URL-адреса, а затем вызывает обработчик.

Пока все хорошо, но я не знаю, как его решить в C++, на PHP это будет легко.

В функции контроллера passegg getControllerCallbacks Я хочу вернуть мои доступные обратные вызовы, но он не будет компилироваться, потому что я не могу наложить указатель функции-члена производного класса на указатель функции-члена (EastereggController) базового класса (контроллер). Я думал о том, что ControllerCallback «класс шаблона», но тогда я должен знать класс контроллера в ControllerHandler, которого я не знаю, потому что у меня есть std :: vector

Я довольно новый для C++, возможно, я что-то упустил.

Это мой код прямо сейчас:

controller.h

#ifndef CONTROLLER_H 
#define CONTROLLER_H 

#include "Config.h" 
#include "Request.h" 
#include "ControllerCallback.h" 

namespace HttpServer { 

class ControllerCallback; 

class Controller { 
    public: 
     Controller(); 
     virtual std::vector<ControllerCallback> getControllerCallbacks() = 0; 

    private: 
     Config *config; 
     const Request *request; 
}; 
} 
#endif // CONTROLLER_H 

EastereggController.h

#ifndef EASTEREGGCONTROLLER_H 
#define EASTEREGGCONTROLLER_H 

#include "../HttpServer/Controller.h" 

namespace Controller { 

    class EastereggController: public HttpServer::Controller { 
     public: 
      EastereggController() {}; 
      std::vector<HttpServer::ControllerCallback> getControllerCallbacks(); 
      HttpServer::Reply easteregg(); 
    }; 
} 

#endif // EASTEREGGCONTROLLER_H 

EastereggController.cpp

#include "EastereggController.h" 

namespace Controller { 
    std::vector<HttpServer::ControllerCallback> EastereggController::getControllerCallbacks() { 
     std::vector<HttpServer::ControllerCallback> controllerCallbacks; 
     HttpServer::ControllerCallback callback; 

     callback.pathTemplate = "/easteregg"; 
     callback.handlerFunctionPtr = &EastereggController::easteregg; 
     return controllerCallbacks; 
    } 

    HttpServer::Reply EastereggController::easteregg() { 
     HttpServer::Reply rep; 
     rep.content.append("you have found an easteregg\n"); 
     rep.status = HttpServer::Reply::ok; 
     rep.headers.resize(2); 
     rep.headers[0].name = "Content-Length"; 
     rep.headers[0].value = std::to_string(rep.content.size()); 
     rep.headers[1].name = "Content-Type"; 
     rep.headers[1].value = "text/plain"; 
     return rep; 
    } 
} 

ControllerCallback.h

#ifndef CONTROLLERCALLBACK_H 
#define CONTROLLERCALLBACK_H 


#include "Reply.h" 
#include <string> 

namespace HttpServer { 

    class Controller; 

    class ControllerCallback { 

     public: 
      ControllerCallback() 
       : pathTemplate("") {}; 
      //,handlerFunctionPtr(nullptr){} 

      std::string pathTemplate; 
      Reply(Controller::*handlerFunctionPtr)(); 
    }; 
} 

#endif 

ControllerHandler.h

#ifndef CONTROLLERHANDLER_H 
#define CONTROLLERHANDLER_H 

#include <vector> 
#include <string> 
#include "Controller.h" 
#include "Config.h" 
#include "Request.h" 
#include "Reply.h" 

namespace HttpServer { 

    class ControllerHandler { 
     public: 
      ControllerHandler(Config &conf); 
      void registerController(Controller &controller); 
      bool invokeController(std::string requestPath, Request &req, Reply &rep); 

     private: 
      Config &config; 
      std::vector<Controller *> controllers; 

    }; 

} 

#endif // CONTROLLERHANDLER_H 

ControllerHandler.cpp

#include "ControllerHandler.h" 
#include "Controller.h" 
#include "PathHandler.h" 

namespace HttpServer { 
    ControllerHandler::ControllerHandler(Config &conf) 
     : config(conf) { 
    } 

    void ControllerHandler::registerController(Controller &controller) { 
     controllers.push_back(&controller); 
    } 

    bool ControllerHandler::invokeController(std::string requestPath, Request &req, Reply &rep) { 
     PathHandler pathHandler(requestPath, ':'); 

     for(Controller *controller : controllers) { 
      std::vector<ControllerCallback> callbacks = controller->getControllerCallbacks(); 
      for(ControllerCallback controllerCallback : callbacks) { 
       if(pathHandler.compare(controllerCallback.pathTemplate)) { 
        rep = ((*controller).*(controllerCallback.handlerFunctionPtr))(); 
        return true; 
       } 
      } 
     } 

     return false; 
    } 
} 
+0

Я думаю, что указатель на функцию-член основан на статическом смещении в классе, который не будет работать с полиморфными типами. Вы хотите виртуальную функцию - передать только ссылку/указатель на объект, а затем вызвать виртуальный метод Reply() объекта. –

+0

, значит, вы должны реализовать логику, в которой функция обработчика находится в классе? –

+0

Я просто предлагаю дать ему объект, а затем вызвать Reply() на этом объекте. Вы все равно можете использовать ту же логику, чтобы найти нужный объект для обработки запроса. –

ответ

0

я, наконец, нашел ответ (который был синтаксическая ошибка, я должен признать)

При попытке различные решения (до размещения здесь) я имел следующий фрагмент:

EastereggController.cpp

callback.handlerFunctionPtr = reinterpret_cast<HttpServer::Reply HttpServer::Controller::*>(&EastereggController::easteregg); 

который был syntactilly неправильно, но я не заметил, потому что я имел следующую ошибку компиляции:

error: invalid cast from type 'HttpServer::Reply (Controller::EastereggController::*)()' to type 'HttpServer::Reply HttpServer::Controller::*()' 
    callback.handlerFunctionPtr = reinterpret_cast<HttpServer::Reply HttpServer::Controller::*()>(&EastereggController::easteregg); 

Теперь правильная версия:

callback.handlerFunctionPtr = reinterpret_cast<HttpServer::Reply(HttpServer::Controller::*)()>(&EastereggController::easteregg); 

только добавил круглые скобки, и теперь он работает.

Смежные вопросы