Klasse an Funktion übergeben. Und auch wieder zurück.



  • Wenn ich das richtig sehe, erfüllt das aber auch nicht meine Anforderungen ...
    Ich kann zwar eine Klasse übergeben (statt einer Funktion), kann sie mir aber nicht zurückgeben und somit auch nicht auf beliebige statische Funktionen selbiger zugreifen.



  • Mit statischen Methoden geht das auch nicht so ohne weiteres. Du könntest dir höchstens ein riesiges switch-statement über die typeid basteln, aber dafür müsstest du vorher alle Klassen kennen, und wirklich schön wärs auch nicht grad. Warum verbieten sich denn virtuelle Funktionen so sehr?



  • Sie verbieten sich nicht wirklich, aber mit statischen wärs einfach schöner gewesen. Folgendes Konstrukt dürfte auch nciht funktionieren, oder?

    class Factory
    {
    public:
        Execute(Key,Func,Par1,Par2)
        {
            Base *Instance =  CreateInstance(Key);
            Instance->Func(Par1,Par2);
            delete Instance;
        }
    };
    

    Dann habe ich faktisch zwar eine Instanz, die ist aber für den User nicht sichtbar, er muss sich also nicht um ihre Verwaltung kümmern



  • Jedenfalls nicht so, wie du es dir vorstellst. Aber für sowas gibt es ja std::auto_ptr. Schau dir mal das Beispiel an, das ich zu meinem Code geschrieben habe, da benutz ich std::auto_ptr, um die Instanz zu kapseln, damit ich mich nicht mehr selbst um das delete kümmern muss.



  • Hallo!
    Ich versuche gerade das Prinzip dieser ClassFactory zu verstehen, aber irgendwie steh ich ganz schön heftig auf der Leitung 😞 Kann es mir mal jemand in Worte fassen? Wozu braucht man zum Beispiel die Klasse basic_factory_helper, wenn die einzig darin vorhandene Funktion sowieso überschrieben wird? Eine Registrierung einer Klasse sieht ja so aus:
    static fku::factory<std::string, A>::register_t<B> reg_b("B");
    Kann mir das Stück Code mal jemand erklären!? Wozu muss bei factory beim Template am Anfang string angegeben werden und dann die Klasse A? Muss da noch die Basisklasse angegeben werden? Wozu? Wäre nett, wenn mir jemand mal das ganze Prinzip in Worte fassen könnte... 😞

    Danke,
    Bis Dann,
    Kevin



  • ich hab mir auch irgendwann mal eine art classfactory aufgebaut, die in etwa so funktionierte:

    class base{...};//hiervon müssen alle klassen die von der factory erstellt werden können erben
    
    class A:public base{...};//eine einfache beispielklasse
    base* createClass(){//eine funktion um die klasse zu erstellen
        return new A;
    }
    //in der main
    factory a;
    a.registerClass("irgendeinName",&createClass);
    A* b=a.create("irgendeinName");
    

    //edit aus dem kopf verschreibsler^^



  • Die basic_factory_helper ist dazu da, dass man das ganze in ner map speicher kann, da eine factory_helper<int> was anderes als ne factory_helper<string> ist benötigt man die gemeinsame basisklasse. Der String ist der Key, der mit in der map gespeichert wird.

    @otze: Das ist ja was ganz anderes ...



  • mir viel grad was ein, die idee ist noch nicht ausgereift und ich hab keine ahnung ob das überhaupt umsetzbar ist, aber vielleicht könnt ihr damit weiterarbeiten, dies ist nur eine art pseudocode:

    class base{};
    template<class T>
    struct derived:public base{
        typedef T valueType;    
    };
    template<class T>void registerClass(std::string a){
        map.insert(pair<base*,std::string>(new derived<T>,a);
    }
    void execute( std::string b){
     *(map.find(b)->second)::valueType::static_func();
    }
    


  • Ich weiss zwar nicht, was das soll, aber falls du den Thread gelesen hättest, wüsstest du, dass das alles schon hier steht ...



  • war halt nur ein lösungsansatz um an den klassentyp selber zu kommen, bisher wurde das ja eher über funktionen versucht, mein lösungansatz ging über typedefs(und der ansatz wurde hier noch nicht genannt 🙄 )



  • Und was ist das dann?

    0xdeadbeef schrieb:

    Whoops, passt wohl doch besser in diesen Thread. Ich hab da mal was geschrieben, was dich interessieren könnte: http://www.dev-geeks.org/forum/viewtopic.php?t=110

    Die Technik, die ich da benutze, basiert auf einer Art Metafunktion. Ich hab eine Hilfsklasse

    struct basic_factory_helper { virtual value_type *create_instance() = 0; };
    

    ...und eine davon abgeleitete template, die ich für jede Klasse, die die Factory verwalten soll, konkretisiere:

    template<typename _t> struct factory_helper : basic_factory_helper {
      virtual value_type *create_instance() { return pointer(new _t()); }
    };
    

    ...wobei value_type ein Parameter der factory, die sinnigerweise auch templatisiert ist, und pointer ein value_type* ist. Auf diese Art kann ich nachher in einer std::map<key_type, basic_factory_helper*> factory_helpers für alle registrierten Klassen speichern und bei Bedarf darauf zugreifen. Die Registrierung geht dann über die template-Methode

    template<typename _t_reg> void register_class(key_type const &k);
    

    ...also z.B. mit

    factory<std::string, Base>::register_class<Derived>("Derived");
    

    Der restliche Code wrappt dieses Prinzip in ein Singleton und stellt ein paar convenience-Funktionen zur Verfügung, damit man nicht immer factory<key, value>::instance().create("foo"); schreiben muss...

    Beiträge sind übrigens nicht so böse gemeint, wie sie sich anhören 😉



  • Und was ist das dann?

    ein anderer ansatz mit ähnlichem interface und einer instanz der klasse, mit dem zwangsläufigen nachteil, dass man keine statischen funktionen von den gespeicherten klassen aufrufen kann?

    aber was weis ich schon^^

    //edit böser rechtschreibfehler kusch, verschwinde 😃



  • Die Instanz gibt's aber erst, wenn man ein create_instance aufruft.
    Wenn man die factory_helper_base und die factory_helper ein wenig abändert, kann man auch ohne probleme statische Funktionen aufrufen:

    struct basic_factory_helper
    {
        virtual value_type *create_instance() = 0;
        virtual void execute()=0;
    };
    
    template<typename _t> struct factory_helper : basic_factory_helper
    {
        virtual value_type *create_instance()
        {
            return pointer(new _t());
        }
        virtual void execute()
        {
            _t::static_function();
        }
    };
    
    void execute( std::string b){
     map.find(b)->second->execute();
    }
    

    Aber ich hab mir deins grad erst richtig angeschaut, muss mal prüfen, ob das net doch was anderes ist 😉



  • @otze: Das mit den typedefs wird nicht hinhauen, weil die bereits zur Compilezeit aufgelöst werden.

    @deUS: Hm. OK, das kann man so machen. Allerdings ist die factory dann auf Klassen beschränkt, die die entsprechenden statischen Funktionen mitliefern. Für meinen Geschmack nicht sonderlich schön, aber über Geschmack kann man bekanntlich lange und ergebnislos streiten. Funktionieren sollte es allemal.



  • Jo, sowas würde ich auch nicht implementieren. Die schönste Möglichkeit wäre es wohl einfach eine instanz auf die struct derived von otze zurückzugeben, dann könnte man beliebige statische funktionen aufrufen, so wie er es in seinem beispiel auch macht, nur eben ausserhalb der klasse.



  • die frage ist nur, wie man an den value_type kommen sollte, immerhin kann man ja von base nicht auf derived casten ohne den template parameter mitzugeben, und einen value_type in base kann man soweit ich weis nicht überschreiben...

    wäre intressant, mal deine implementation zu sehen, falls dus schaffen solltest 🙂



  • #include <iostream>
    
    struct A { static void foo() { std::cout << 'A' << std::endl; } };
    struct B : public A { static void foo() { std::cout << 'B' << std::endl; } };
    
    int main() {
      A *p = new B;
      p->foo();
      delete p;
    }
    

    Ausgabe:

    A
    

    statische Funktionsaufrufe werden zur Compilezeit aufgelöst. Auf die Art kommt ihr nicht weiter.



  • @otze:
    Oha, da hab ich garnicht dran gedacht ... Mist 😞



  • da die templateparameter ja eh zur compilezeit ausgewertet werden, und wir darum nichts dynamisches damit zustande bringen könnten,könnten wir das dann nicht alternativ auf einer typliste basieren lassen? 🙂

    //pseudocode
    class A{};
    class B{};
    class C{};
    typedef typelist<A,B,C> myClasses;
    //irgendwo in irgendeiner klasse/funktion
    getType<myClasses,2>::value_type::static_func();
    


  • Das kannst du meinetwegen machen, aber es ist bei weitem nicht so mächtig wie eine factory. Es bringt nur dann was, wenn du vorher alle Klassen kennst, die die Factory rausschmeißen soll, und bringt dir also z.B. für Plugin-Architekturen aller Art so rein gar nichts.


Anmelden zum Antworten