Map von Pointern auf Membervariablen



  • Also ich habe verschiedene Klassen mit unterschiedlichen Membervariablen. Beim Programmstart also zur Laufzeit wird nun eine Datei eingelesen. Damit bekomme ich Variablennamen und die zugehörigen Werte (beides als String) geliefert.
    Das macht Probleme:
    - Wie ordne ich dem Variablennamenstring die zugehörige Variable zu?
    Meine Lösung (siehe dieser Thread): Eine Map in der ich einen Zeiger auf jede Variable mit dem Namen der Variable als Key speichere.

    - Wie überliefere ich der Variablen (über den Zeiger) einen Wert?
    Meine Lösung (siehe dieser Thread): virtuelle Assign Funktion

    - Wie bekomme ich den Typ dieser Variablen?
    Meine Lösung: Alle Klassen bekommen im Grunde einen statischen String mit ihrem Namen verpasst

    - Wie erzeuge ich nun ein Objekt aus diesen Informationen?
    Meine Lösung: Factory Klasse wo alle Klassen registriert werden

    Und noch ganz wichtig. Die Library soll erweiterbar sein. D.h. ich muss auch Objekte erzeugen können, die ein Nutzer meiner Lib registriert hat.



  • Ah okay, das ist eine gute Beschreibung 🙂
    Im Prinzip ist es diese Problematik, oder?

    Man könnte sowas machen:

    struct MyClass
    {
        Int i;    // Alle
        Double d; // abgeleitet
        String s; // von Object
    
        std::map<const char*, Object*> catalog;
    
        // Wird mit getrennten Strings aus Datei gefüttert
        void WriteValue(const std::string& var, const std::string& value)
        {
            // z.B. var = "i", value = "37"
            auto itr = catalog.find(var.c_str());
            if (itr == catalog.end())
                throw std::runtime_error("Variable nicht vorhanden");
            itr->Write(value);
        }
    }
    

    Und eine solche Klasse könnte so aussehen:

    class Int : public Object
    {
        public:
            virtual void Write(const std::string& s)
            {
               std::istringstream stream(s);
               stream >> i;
               // Bei fail() oder noch weiteren Zeichen Exception
            }
    
        private:
            int i;
    }
    

    Und zum Auslesen könntest du das Umgekehrte machen:

    virtual std::string Read() const;
    


  • Ok, das habe ich ja sogar so implementiert, komme damit auch fast überall zurecht. Aber was wenn ich anstatt eines Strings doch ein Objekt gleichen Typs zuordnen möchte?

    Wenn man Deep-Copy-Semantik möchte, ohne den dynamischen Typen zu kennen, kann man z.B. das Clone-Idiom anwenden.
    Dann überschreibt man gleich den (Smart-)Pointer und nicht nur das Objekt, wodurch auch Slicing verunmöglicht wird.
    

    Meist du wirklich Clone-Idiom oder die Virtual-Constructor-Methode? Ich habe also mal der Klasse Object die virtuelle Funktion Get hinzugefügt und entsprechend in der Double Klasse überschrieben. Das soll ja gehen solange man nur den Rückgabewert verändert.

    Double* Double::Get()
    {
    	return this;
    }
    

    Und hier wieder der Testcode:

    Double d = 320;
    Object* e = &d;
    
    std::wcout << d << std::endl;
    *e->Get() = Double(640);
    std::wcout << d << std::endl;
    

    d ist aber trotzdem noch 320. So geht es also nicht. Kannst du mir evtl. nochmal ein Codebeispiel geben wie du die Implementierung gemeint hast?



  • Student83 schrieb:

    Ok, das habe ich ja sogar so implementiert, komme damit auch fast überall zurecht. Aber was wenn ich anstatt eines Strings doch ein Objekt gleichen Typs zuordnen möchte?

    Das kannst du ja immer noch direkt an den Integer . Oder was für eine Situation gibt es, in der du nur das abstrakte Object kennst und diesem einen int übergeben willst?

    Student83 schrieb:

    Meist du wirklich Clone-Idiom oder die Virtual-Constructor-Methode?

    Ich meinte schon Clone. Aber du musst unterscheiden zwischen Umwandlung/Parsen ("37" -> Integer(37)) und Kopieren (Integer(37) -> Integer(37)). Schau dir am besten das Clone-Idiom irgendwo an, bei Wikibooks oder so.

    Student83 schrieb:

    Ich habe also mal der Klasse Object die virtuelle Funktion Get hinzugefügt und entsprechend in der Double Klasse überschrieben. Das soll ja gehen solange man nur den Rückgabewert verändert.

    Ja, aber mit deinem return this; baust du nur den Adressoperator nach.

    Wenn du dir sicher bist, dass es ein Double ist, dann caste eben.

    Object* e = new Double(1.5);
    static_cast<Double*>(e)->SetValue(3.24);
    delete e;
    

    Und wenn du nicht sicher bist, benutze die genannten Abstraktionsmechanismen. Wenn sich diese nicht anwenden lassen, ist dein Design wahrscheinlich nicht ideal.


Anmelden zum Antworten