registrieren Wenn eine MessageFactory Klasse Umsetzung Message-Objekte I wie etwas verwendet, um instatiate:Dynamisch Konstruktormethoden in einem Abstract bei der Kompilierung mit C++ Vorlagen
class MessageFactory
{
public:
static Message *create(int type)
{
switch(type) {
case PING_MSG:
return new PingMessage();
case PONG_MSG:
return new PongMessage();
....
}
}
Dies funktioniert ok, aber jedes Mal, wenn ich hinzufügen, eine neue Nachricht Ich habe um eine neue XXX_MSG hinzuzufügen und die switch-Anweisung zu ändern.
Nach einigen Nachforschungen fand ich eine Möglichkeit, die MessageFactory während der Kompilierung dynamisch zu aktualisieren, so dass ich beliebig viele Nachrichten hinzufügen kann, ohne die MessageFactory selbst ändern zu müssen. Dies ermöglicht saubere und einfachen Code zu halten, wie ich brauche, um Nachrichtenklassen nicht zu ändern drei verschiedene Orte hinzufügen/entfernen: durch die Registrierung in die MessageFactory Klasse, alle neue Meldeklassen
#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;
}
Die Vorlage hier funktioniert die Magie (zB PingMessage und PongMessage) diese Unterklasse von MessageTmpl.
Dies funktioniert gut und vereinfacht die Wartung Code aber ich habe noch einige Fragen zu dieser Technik haben:
Ist das eine bekannte Technik/Muster? wie heißt? Ich möchte mehr Informationen darüber suchen.
Ich möchte zum Speichern neuer Konstrukteure das Array machen MessageFactory :: m_List [65536] ein std :: map aber dabei wird das Programm selbst segfault vor Haupt erreichen(). Erstellen eines Arrays von 65536 Elementen ist Overkill, aber ich habe keinen Weg gefunden, dies zu einem dynamischen Container zu machen.
Für alle Nachrichtenklassen, die Unterklassen von MessageTmpl sind, muss ich den Konstruktor implementieren. Wenn nicht, wird es nicht in der MessageFactory registriert.
Zum Beispiel den Konstruktor der PongMessage Kommentierung:
class PongMessage: public MessageTmpl < 11, PongMessage > { public: //PongMessage() {} /* HERE */ virtual void say() { printf("Pong\n"); } };
in der PongMessage Klasse würde nicht von der MessageFactory registriert wird und das Programm würde segfault im MessageFactory :: Create (11) Linie . Die Frage ist
warum die Klasse nicht registriert? Die leere Implementierung der 100+ Nachrichten, die ich brauche hinzuzufügen, fühlt sich ineffizient und unnötig an.
# 1 ist CRTP (Sorten) http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – Anycorn
# 3, weil Konstruktor MessageTmpl geschützt ist (vielleicht) – Anycorn
durch die Art und Weise, überprüfen Sie Ihre Codeliste. es hat Streuner; und . Figuren. Ich habe es kompiliert, aber ich bekomme einen Segmentierungsfehler. – Anycorn