Je travaille actuellement sur un HttpServer et ont le problème suivant:C++ pointeur d'acteur de classe dérivée de pointeur de classe de base
Je veux enregistrer mes contrôleurs et quand je reçois une demande que je veux vérifier si un de ces contrôleurs a un gestionnaire pour l'URL demandée, puis appeler le gestionnaire. Jusqu'ici tout va bien, mais je ne sais pas comment le résoudre en C++, en PHP ce serait facile. Dans la fonction de contrôleur Easteregg getControllerCallbacks, je souhaite renvoyer mes rappels disponibles mais ne compilera pas car je ne peux pas convertir un pointeur de fonction membre d'une classe dérivée en un pointeur de fonction membre (EastereggController) de la classe de base (Manette). J'ai pensé faire du ControllerCallback un "template class" mais ensuite je dois connaître la classe du Controller dans le ControllerHandler, que je ne connais pas car j'ai un std :: vector
Je suis assez nouveau en C++, j'ai peut-être oublié quelque chose.
Ceci est mon code maintenant:
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;
}
}
Je pense que le pointeur vers la fonction membre est basé sur un décalage statique dans la classe, qui ne fonctionnera pas avec les types polymorphes. Vous voulez une fonction virtuelle - passez juste une référence/pointeur vers l'objet, puis appelez la méthode virtuelle Reply() de l'objet. –
donc vous voulez dire que je devrais implémenter la logique où la fonction de gestionnaire est trouvée dans la classe? –
Je suggérais juste de lui donner un objet puis d'appeler Reply() sur cet objet. Vous pouvez toujours utiliser la même logique pour trouver le bon objet pour gérer la requête. –