Funktionspointer auf Constructor, bzw. Erstellung von unbekannter Klasse @ Runtime
-
if(strcmp(url, "/") == 0 || strcmp(url, "/login") == 0) { *conData = (void*)(connectionInfo = new LoginPage(connection, httpMethod)); } else if(strcmp(url, "/logout") == 0) { *conData = (void*)(connectionInfo = new LogoutPage(connection, httpMethod)); } else if(strcmp(url, "/list/emails") == 0) { *conData = (void*)(connectionInfo = new ListEmailPage(connection, httpMethod)); } else if(strcmp(url, "/create/email/or/change/pass") == 0) { *conData = (void*)(connectionInfo = new CreateEmailOrChangePassPage(connection, httpMethod)); } else if(strcmp(url, "/delete/email") == 0) { *conData = (void*)(connectionInfo = new DeleteEmailPage(connection, httpMethod)); }Ich programmiere ein bisschen HTTP Funktionalität in C++ und weiß gerade nicht, wie man das hier in eine Map<std::string, ???> packen kann? Ein Funktionspointer geht ja schlecht auf nen Constructor (ist wohl auch verboten nach Standard, wie mir Google sagt), was mach ich also hier?
Die Klassen sind natürlich alle Kinder einer Base Klasse (bzw. in diesem Fall ist conData sogar ein void** Pointer, jaja, diese C libraries immer).
PS: Die Idee, static Member Funktionen zu schreiben, die nichts anderes machen, als das Objekt zu erzeugen und zurückzugeben, hatte ich schon. Und dann darauf natürlich Funktionspointer zu setzen.. Aber vielleicht gibt es ja noch etwas eleganteres..
mfg~
-
Du könntest deine Objekte gemäss einem Prototype erzeugen
Prototype PatternOder Du könntest das Abtract Factory Pattern anwenden. Dabei werden dann Konkrete Factories in der Map gehalten.
Simon
-
Du könntest dir eine Factory mit statischen Methoden anlegen und diese dann in die Map eintragen (als normale Funktionspointer).
So in der Art:class Factory { static ConnectionBase* CreateLoginPage(const string& connection, const string& httpMethod) { return new LoginPage(connection, httpMethod); } // ... }; typedef ConnectionBase* (*ConnFunc)(const string& connection, const string& httpMethod); std::map<std::string, ConnFunc> conn_map; conn_map["/login"] = Factory::CreateLoginPage; ... // Zugriff std::map::iterator it = conn_map.find(url); if(it != conn_map.end()) { connectionInfo = it->second(connection, httpMethod); }Ich hoffe, du verstehst diesen Ansatz?
Und auf den 'void**' solltest du in dem Programm verzichten (sondern nur beim Zugriff auf die Lib entsprechend 'casten')!
-
Th69 schrieb:
Und auf den 'void**' solltest du in dem Programm verzichten (sondern nur beim Zugriff auf die Lib entsprechend 'casten')!
Das muss ich leider an der Stelle so machen (der void** Pointer ist quasi der Zugriff auf die Library)
Prototyping passt da nicht so, aber diese Factory ist ganz interessant.
Nur wo ist der Unterschied zwischen ner Factory und dass jede Klasse ihre eigene create Methode hätte?
class LoginPage { static LoginPage* create(Connection* connection, HttpMethod httpMethod) { return new LoginPage(connection, httpMethod); } // ... };mfg~
-
Ohne großen zusätzlichen Aufwand für jede Klasse gehts auch so:
#include <iostream> #include <string> #include <map> #include <boost/shared_ptr.hpp> using namespace std; using namespace boost; template <class Object_> class object_creator { public: typedef Object_ object_type; virtual ~object_creator() { } virtual object_type *create() = 0; }; template <class Creator_, class Object_> class special_creator : public Creator_ { typename Creator_::object_type *create() { return new Object_(); } }; class page { public: virtual ~page() { } virtual void print() { cout << "page" << endl; } }; class login_page : public page { public: void print() { cout << "login" << endl; } }; typedef object_creator<page> page_creator; int main() { map<string, shared_ptr<page_creator> > creators; creators["/login"].reset(new special_creator<page_creator, login_page>()); shared_ptr<page>(creators["/login"]->create())->print(); cin.get(); }So fällt zwar die Möglichkeit weg, das Object per Konstruktor mit Argumenten zu befüllen, aber das lässt sich auch mit
init()oder so machen.
-
TyRoXx schrieb:
Ohne großen zusätzlichen Aufwand für jede Klasse gehts auch so:
Danke, das sieht nach einer optimalen Lösung aus!
TyRoXx schrieb:
So fällt zwar die Möglichkeit weg, das Object per Konstruktor mit Argumenten zu befüllen, aber das lässt sich auch mit
init()oder so machen.Da ich immer die gleichen 2 Parameter habe, sollte doch das Template anpassbar sein, für diese Parameter, oder?
mfg~
-
NewSoftzzz schrieb:
Da ich immer die gleichen 2 Parameter habe, sollte doch das Template anpassbar sein, für diese Parameter, oder?
Ich habe ein wenig experimentiert und das ganze in leicht veränderter Form für bis zu 3 beliebige Parameter gemacht. Weiß jemand, ob es das schon in Boost gibt? Dann wäre es nämlich unnötig, meine unordentliche Lösung zu verwenden.
#include <iostream> #include <string> #include <map> #include <boost/shared_ptr.hpp> using namespace std; using namespace boost; struct null_type { }; template <class Base_, class Arg1 = null_type, class Arg2 = null_type, class Arg3 = null_type> class ctor_ptr_base { public: typedef Base_ base_t; virtual ~ctor_ptr_base() { } virtual base_t * operator ()() const { return 0; } virtual base_t * operator ()(const Arg1 &arg1) const { return 0; } virtual base_t * operator ()(const Arg1 &arg1, const Arg2 &arg2) const { return 0; } virtual base_t * operator ()(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) const { return 0; } }; template <class T, class Base, class Arg1 = null_type, class Arg2 = null_type, class Arg3 = null_type> class ctor_ptr_impl : public ctor_ptr_base<Base, Arg1, Arg2, Arg3> { public: base_t * operator ()(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) const { return new T(arg1, arg2, arg3); } }; template <class T, class Base> class ctor_ptr_impl<T, Base> : public ctor_ptr_base<Base> { public: typename base_t * operator ()() const { return new T(); } }; template <class T, class Base, class Arg1> class ctor_ptr_impl<T, Base, Arg1> : public ctor_ptr_base<Base, Arg1> { public: base_t * operator ()(const Arg1 &arg1) const { return new T(arg1); } }; template <class T, class Base, class Arg1, class Arg2> class ctor_ptr_impl<T, Base, Arg1, Arg2> : public ctor_ptr_base<Base, Arg1, Arg2> { public: base_t * operator ()(const Arg1 &arg1, const Arg2 &arg2) const { return new T(arg1, arg2); } }; template <class Base, class Arg1 = null_type, class Arg2 = null_type, class Arg3 = null_type> class ctor_ptr { public: template <class T> void setType() { m_base.reset(new ctor_ptr_impl<T, Base, Arg1, Arg2, Arg3>()); } Base *operator ()(const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) const { return (*m_base.get())(arg1, arg2, arg3); } private: boost::shared_ptr<ctor_ptr_base<Base, Arg1, Arg2, Arg3> > m_base; }; template <class Base> class ctor_ptr<Base> { public: template <class T> void setType() { m_base.reset(new ctor_ptr_impl<T, Base>()); } Base *operator ()() const { return (*m_base)(); } private: boost::shared_ptr<ctor_ptr_base<Base> > m_base; }; template <class Base, class Arg1> class ctor_ptr<Base, Arg1> { public: template <class T> void setType() { m_base.reset(new ctor_ptr_impl<T, Base, Arg1>()); } Base *operator ()(const Arg1 &arg1) const { return (*m_base)(arg1); } private: boost::shared_ptr<ctor_ptr_base<Base, Arg1> > m_base; }; template <class Base, class Arg1, class Arg2> class ctor_ptr<Base, Arg1, Arg2> { public: template <class T> void setType() { m_base.reset(new ctor_ptr_impl<T, Base, Arg1, Arg2>()); } Base *operator ()(const Arg1 &arg1, const Arg2 &arg2) const { return (*m_base)(arg1, arg2); } private: boost::shared_ptr<ctor_ptr_base<Base, Arg1, Arg2> > m_base; }; class page { public: page(int i) { cout << "ctor page " << i << endl; } virtual ~page() { cout << "dtor page" << endl; } }; class login_page : public page { public: login_page(int i) : page(i) { cout << "ctor login_page" << endl; } virtual ~login_page() { cout << "dtor login_page" << endl; } }; class logout_page : public page { public: logout_page(int i) : page(i) { cout << "ctor logout_page" << endl; } virtual ~logout_page() { cout << "dtor logout_page" << endl; } }; int main() { { map<string, ctor_ptr<page, int> > ctors; ctors["/login"].setType<login_page>(); ctors["/logout"].setType<logout_page>(); page *p = ctors["/login"](123); delete p; } cin.get(); }
-
Es gibt auf jeden Fall boost::bind für solche Sachen mit normalen Funktionen, aber ich hab keine Ahnung, ob das wiederum für Ctors funktionieren würde..
http://www.boost.org/doc/libs/1_41_0/libs/bind/bind.html
mfg~
-
Hey, ich habe gerade etwas gefunden, was vllt. benutzbar ist:
Ich schau's mir jetzt mal an..
mfg, René~