Lors de l'implémentation d'une classe MessageFactory à instatiate objets de message que j'ai utilisé quelque chose comme:registre Dynamiquement méthodes de constructeur Abstraite au moment de la compilation en utilisant des modèles C++
class MessageFactory
{
public:
static Message *create(int type)
{
switch(type) {
case PING_MSG:
return new PingMessage();
case PONG_MSG:
return new PongMessage();
....
}
}
Cela fonctionne ok, mais chaque fois que j'ajouter un nouveau message que je pour ajouter un nouveau XXX_MSG et modifier l'instruction switch. Après quelques recherches, j'ai trouvé un moyen de mettre à jour dynamiquement MessageFactory à la compilation afin que je puisse ajouter autant de messages que je veux sans avoir besoin de modifier le MessageFactory lui-même. Cela permet plus propre et plus facile à maintenir le code que je ne ai pas besoin de modifier trois endroits différents pour ajouter/supprimer des classes de message:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
class Message
{
protected:
inline Message() {};
public:
inline virtual ~Message() { }
inline int getMessageType() const { return m_type; }
virtual void say() = 0;
protected:
uint16_t m_type;
};
template<int TYPE, typename IMPL>
class MessageTmpl: public Message
{
enum { _MESSAGE_ID = TYPE };
public:
static Message* Create() { return new IMPL(); }
static const uint16_t MESSAGE_ID; // for registration
protected:
MessageTmpl() { m_type = MESSAGE_ID; } //use parameter to instanciate template
};
typedef Message* (*t_pfFactory)();
class MessageFactory⋅
{
public:
static uint16_t Register(uint16_t msgid, t_pfFactory factoryMethod)
{
printf("Registering constructor for msg id %d\n", msgid);
m_List[msgid] = factoryMethod;
return msgid;
}
static Message *Create(uint16_t msgid)
{
return m_List[msgid]();
}
static t_pfFactory m_List[65536];
};
template <int TYPE, typename IMPL>
const uint16_t MessageTmpl<TYPE, IMPL >::MESSAGE_ID = MessageFactory::Register(
MessageTmpl<TYPE, IMPL >::_MESSAGE_ID, &MessageTmpl<TYPE, IMPL >::Create);
class PingMessage: public MessageTmpl < 10, PingMessage >
{⋅
public:
PingMessage() {}
virtual void say() { printf("Ping\n"); }
};
class PongMessage: public MessageTmpl < 11, PongMessage >
{⋅
public:
PongMessage() {}
virtual void say() { printf("Pong\n"); }
};
t_pfFactory MessageFactory::m_List[65536];
int main(int argc, char **argv)
{
Message *msg1;
Message *msg2;
msg1 = MessageFactory::Create(10);
msg1->say();
msg2 = MessageFactory::Create(11);
msg2->say();
delete msg1;
delete msg2;
return 0;
}
Le modèle fait ici la magie en vous inscrivant dans la classe MessageFactory, toutes les nouvelles classes de messages (par exemple PingMessage et PongMessage) cette sous-classe de MessageTmpl.
Cela fonctionne très bien et simplifie la maintenance du code mais j'ai encore quelques questions au sujet de cette technique:
Est-ce une technique connue/modèle? quel est le nom? Je veux rechercher plus d'informations à ce sujet.
Je veux faire le tableau pour stocker de nouveaux constructeurs MessageFactory :: m_List [65536] std :: carte, mais cela pourrait provoquer des programme à atteindre avant même segmentation fault main(). Créer un tableau de 65536 éléments est exagéré, mais je n'ai pas trouvé un moyen de en faire un conteneur dynamique. Pour toutes les classes de message qui sont des sous-classes de MessageTmpl, je dois implémenter le constructeur . Sinon, il ne sera pas enregistré dans la MessageFactory.
Par exemple commentant le constructeur de la PongMessage:
class PongMessage: public MessageTmpl < 11, PongMessage > { public: //PongMessage() {} /* HERE */ virtual void say() { printf("Pong\n"); } };
entraînerait la classe PongMessage ne pas être enregistrée par le MessageFactory et le programme aurait segfault dans le MessageFactory :: Créer (11) ligne . La question est
pourquoi la classe ne s'enregistrera pas? Devoir ajouter l'implémentation vide des 100+ messages dont j'ai besoin me semble inefficace et inutile.
# 1 est CRTP (sortes de) http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – Anycorn
# 3 parce que constructeur de MessageTmpl est protégé (peut-être) – Anycorn
par la manière, vérifiez votre liste de code. il a erré; et . personnages. Je l'ai compilé, mais je reçois une erreur de segmentation. – Anycorn