Variable in Klasse von ausserhalb abändern?



  • dark alex schrieb:

    Hi!

    Ich stelle mein Problem mal knapp dar, ich denke es ist einfach zu sehen, was ich will:

    Main.cpp

    [...]
    #include "Client.h"
    [...]
    
    int main (void)
    {
       [...]
       ClientVars CVInstance;
       cout << "Aktueller Wert: " << CVInstance.VarName << endl;
       CVInstance.VarName = 2000; //Zeile 57
       cout << "Neuer Wert sollte 2000 sein: " << CVInstance.VarName;
       [...]
    }
    
    [...]
    

    Erstmal: Wozu bruach ich das? Ist doch sinnlos! - Ich habe meine Gründe 😉
    Nimm' doch einfach normale lokale Variablen! -> Siehe Satz vorher!

    Evtl wäre es noch gut zu wissen, wie die Klasse aussieht:

    Client.h:

    class ClientVars
    {
    public:
    	ClientVars(); //Constructor
    	~ClientVars(); //Terminator ]:~§    Destructor
    
    	int VarName;
    };
    

    Client.cpp:

    #include "Client.h"
    
    ClientVars::ClientVars()
    {
    	VarName = 150;
    }
    
    ClientVars::~ClientVars()
    {
    	//blubb... ;-)
    }
    

    Und was iss jetzt dein Problem?

    1>.\Main.cpp(57) : error C2106: '=': Linker Operand muss ein L-Wert sein

    Der Code der Main.cpp ist nur ein Ausschnitt. Werden weitere Daten benötigt, bitte fragt einfach danach!

    Kommentiere ich zeile 57 aus, so gibt er mir zweimal 150 aus - korrekter weise. Ich möchte nun aber dass er mir beim zweiten mal die 2000 ausgibt, die er vorher zuweisen soll -> Fehler

    Sollte das nicht möglich sein, wie könnte ich das anders lösen? (ICh muss diese variable in dieser klasse irgendwie ändern. Aber: EIne klassenfunktion schreien für diese einzige Var geht nicht, da ich wenn ich fertig bin sehr viele Variablen haben werde in dieser Klasse.



  • dark alex schrieb:

    Aber: EIne klassenfunktion schreien für diese einzige Var geht nicht, da ich wenn ich fertig bin sehr viele Variablen haben werde in dieser Klasse.

    Die Begründung klingt jz nicht soooo logisch... Dann musst du halt 20 Setter und 20 Getter schreiben...

    mal davon abgesehen:

    int main(void) in C++ wird ein void in der Parameterliste oft als schlechter Stil angesehen - lass es einfach weg...

    Zu deinem Fehler kann ich leider nichts sagen...
    Ich könnte mir nur vorstellen, dass du dort vll ein const ClientVars CVInstance; stehen hast...

    Die Frage, wozu du das brauchst, wäre trotzdem mal interessant ^^

    bb



  • 1. Der:

    ]:~§

    sieht aus, wie ein Taliban. 🙂

    2. Initialisierungsliste:

    ClientVars::ClientVars()
    :
    VarName ( 150 )
    {
    }
    

    3. Macht man das normalerweise mittels Getter/Setter. Siehe Kapselung usw.

    4. Sollte das so gehen. VarName ist ein L-Wert..



  • ^^

    Ich habe mehrere CPP-Quelldateien, und damit mehrere Namespaces/Klassen, die cooperieren 😉

    Nun muss ich biem laden:
    -Einstellungen in variablen ablegen
    -Ein paar andere Informationen ablegen

    In bestimmten situationen:
    -Weitere Informationen ablegen
    -Manche Informationen ändern

    Aber auf genannte Informationen muss ich von allen Dateien aus zugreifen können.
    Info: Natürlich ist der code in der main etwas anders, ich hol mir die Instanz der ClientVars Klasse über eine Singleton-ähnliche Funktion, was auch funktioniert, weil er mir die 150 ja ausgibt, wenn ich das schreiben in die Variable auskommentiere.

    Ist es irgendwie möglich, dass ich mit Settern über parameter angeben kann welche var ich ändere? Also so wie es in PHP so lösbar wäre:

    function SetVar($name, $value)
    {
        global $$name; //Das lässt mich in der Funktion auf die externe Variable zugreifen. Ist in C++ ja vernachlässigbar
        $$name = $value;
    }
    


  • Ist es irgendwie möglich, dass ich mit Settern über parameter angeben kann welche var ich ändere?

    Nein, ist es nicht. C++ ist, nicht wie PHP eine dynamische Sprache. Du musst dir da jeden Setter/Getter speziell für die Variable schreiben. (Ist ja nicht so tratisch, ist schnell geschrieben).



  • dark alex schrieb:

    Ist es irgendwie möglich, dass ich mit Settern über parameter angeben kann welche var ich ändere?

    In etwa, ja, allerdings mit etwas geändertem Design. Was wahrscheinlich sowieso nicht schlecht wäre, wenn du, wie du schreibst, "sehr viele Variablen" in deiner Klasse haben willst.

    class Config
    {
        public:
            int getVar( const std::string& name, int default ) const
            {
                std::map<std::string,int>::const_iterator pos = m_vars.find( name );
                if ( pos == m_vars.end() )
                    return default;
                return pos->second;
            }
    
            void setVar( const std::string& name, int value )
            {
                m_vars[name] = value;
            }
    
        private:
            std::map<std::string,int> m_vars;
    };
    

    Verwendet man manchmal, wenn man Error-Codes oder Einstellungen hat, die man aus einer Datei liest.

    Wird halt nur umständlicher, wenn die Variablen verschiedene Typen haben - es kommt halt auf den konkreten Fall drauf an, ob sich solch eine map sinnvoll einsetzen lässt.



  • Ja, ist aber alles andere als sauber und solltest du besser nicht machen:

    #include <iostream>
    #include <map>
    #include <cassert>
    
    class Foo {
    public:
    	Foo()
    	{
    		AddVar("var1", var1);
    		AddVar("var2", var2);
    		AddVar("var3", var3);
    		AddVar("var4", var4);
    	}
    
    	template <typename T>
    	void Set(const std::string& varname, T value)
    	{
    		assert(vars_[varname] != 0);
    		*reinterpret_cast<T*>(vars_[varname]) = value;
    	}
    
    	template <typename T>
    	T Get(const std::string& varname)
    	{
    		return *reinterpret_cast<T*>(vars_[varname]);
    	}
    private:
    	std::map<std::string, void*> vars_;
    	int var1;
    	double var2;
    	std::string var3;
    	char var4;
    
    	template <typename T>
    	void AddVar(const std::string& name, T& p)
    	{
    		vars_[name] = reinterpret_cast<void*>(&p);
    	}
    };
    
    int main()
    {
    	Foo foo;
    	foo.Set("var1", 42);
    	foo.Set("var2", 13.37);
    	foo.Set<std::string>("var3", "Hallo Welt");
    	foo.Set("var4", '!');
    	std::cout << foo.Get<int>("var1") << "\n"
    	          << foo.Get<double>("var2") << "\n"
    	          << foo.Get<std::string>("var3")
    	          << foo.Get<char>("var4") << std::endl;
    }
    

    (Gibt aber bestimmt noch bessere Möglichkeiten)



  • Badestrand schrieb:

    dark alex schrieb:

    Ist es irgendwie möglich, dass ich mit Settern über parameter angeben kann welche var ich ändere?

    In etwa, ja, allerdings mit etwas geändertem Design. Was wahrscheinlich sowieso nicht schlecht wäre, wenn du, wie du schreibst, "sehr viele Variablen" in deiner Klasse haben willst.

    class Config
    {
        public:
            int getVar( const std::string& name, int default ) const
            {
                std::map<std::string,int>::const_iterator pos = m_vars.find( name );
                if ( pos == m_vars.end() )
                    return default;
                return pos->second;
            }
    
            void setVar( const std::string& name, int value )
            {
                m_vars[name] = value;
            }
    
        private:
            std::map<std::string,int> m_vars;
    };
    

    Verwendet man manchmal, wenn man Error-Codes oder Einstellungen hat, die man aus einer Datei liest.

    Wird halt nur umständlicher, wenn die Variablen verschiedene Typen haben - es kommt halt auf den konkreten Fall drauf an, ob sich solch eine map sinnvoll einsetzen lässt.

    Darauf hätte ich ja auch kommen können 😣 Danke!



  • mist...

    Client.cpp

    void ClientVars::setInt( const std::string& name, int value )
    {
    	m_ints[name] = value;
    	cout << "Setting ClientVar<int> " << name << " to " << value << endl;
    }
    

    Main.cpp

    cout << "testGlobal 150: " << glob.getInt((std::string)"testGlobal",0) << endl;
    	glob.setInt((std::string)"testGlobal",2000);
    	cout << "testGlobal 150->2000: " << glob.getInt((std::string)"testGlobal",0) << endl;
    

    Ausgabe:

    testGlobal 150: 150
    Setting ClientVar<int> testGlobal to 2000
    testGlobal 150->2000: 150
    

    ... lol ... Woran kann das liegen?



  • Die C-Casts würde ich weglassen. Wie sieht denn die getInt-Funktion aus?



  • so:

    int ClientVars::getInt( std::string name, int default )
    {
        std::map<std::string,int>::const_iterator pos = m_ints.find( name );
        if ( pos == m_ints.end() )
            return default;
        return pos->second;
    }
    


  • Zeig mal minimalen aber kompilier- und linkfähigen Source. Das hier funktioniert jedenfalls:

    class ClientVars
    {
        // Inhalt wie in Klasse "Config" von ein paar Posts drüber
    }; 
    
    int main()
    {
    	ClientVars x;
    	x.setVar( "Hallo", 123 );
    	std::cout << x.getVar("Hallo",0) << std::endl; // 123
    }
    


  • Bei mir klappt's:

    #include <iostream>
    #include <map>
    #include <string>
    
    using namespace std;
    
    class ClientValues {
    public:
    	void setInt( const std::string& name, int value )
    	{
    		m_ints[name] = value;
    		cout << "Setting ClientVar<int> " << name << " to " << value << endl;
    	}
    	int getInt( std::string name, int defaultV )
    	{
    		std::map<std::string,int>::const_iterator pos = m_ints.find( name );
    		if ( pos == m_ints.end() )
    			return defaultV;
    		return pos->second;
    	}
    private:
    	std::map<std::string, int> m_ints;
    };
    
    int main()
    {
    	ClientValues glob;
    	glob.setInt("testGlobal", 150);
    	std::cout << "testGlobal 150: " << glob.getInt("testGlobal", 0) << std::endl;
    	glob.setInt("testGlobal", 2000);
    	std::cout << "testGlobal 150->2000: " << glob.getInt("testGlobal", 0) << std::endl;
    }
    
    Setting ClientVar<int> testGlobal to 150
    testGlobal 150: 150
    Setting ClientVar<int> testGlobal to 2000
    testGlobal 150->2000: 2000
    

    Sicher dass du den Startwert von 150 auch mit setInt gesetzt hast?



  • dark alex schrieb:

    so:

    int ClientVars::getInt( std::string name, int default )
    

    Das default wird nicht ohne Grund blau formatiert; es ist ein Schlüsselwort der Sprache und kann als solches nicht für Bezeichner verwendet werden.



  • Nexus schrieb:

    kann als solches nicht für Bezeichner verwendet werden.

    Mit dem richtigen Compiler geht alles 🤡


Log in to reply