Struct, Pointer, Reference



  • Dann fasse ich das mal in worte 🙂
    Ich wollte mir die Adresse der original MySQL-Verbindung sicher.
    Dann wollte ich die Adresse von MyClass->mysql auf die Adresse der neuen Verbindung zeigen lassen, damit die Funktionen mit der neuen Arbeiten. Zum schluss wollte ich, das MyClass->mysql wieder die alte Verbingung darstellt...

    Normalerweise arbeite ich immer mit Zeigern auf Objekte, da kann ich ganz easy tauschen, aber wie mache ich das in diesem Fall....?



  • Es gibt 2 Möglchkeiten: entweder ist MyClass->mysql ein pointer, dann muss es so heißen:

    MYSQL *original=&(MyClass->mysql);
    

    weil du sonst an einen pointer auf MYSQL die Adresse eines pointers auf MYSQL zuweist (schauder)

    oder aber MyClass->mysql ist ein Objekt vom Typ MYSQL, dann muss es heißen

    MyClass->mysql=(neu);
    //Funktionen aufrufen
    (MyClass->mysql) = *original;
    

    weil du den Objekten halt auch wieder Objekte zuweisen musst.

    Abgesehen davon (da du ja selbst sagst du hast es mit den pointern noch nicht so ganz raus):

    MyClass ist ein Zeiger auf ein Struct oder ein Objekt, das ein Datenmember namens mysql hat, welches wie oben beschrieben entweder ein pointer auf ein MYSQL-objekt oder selbst vom Typ MYSQL ist.

    Falls es sich bei MyClass um ein Objekt irgendeiner Klasse handelt, solltest du noch folgendes beachten:
    - mysql muss public deklariert sein, damit du von außen Zugriff bekommst.
    - es ist allgemein schlechter Stil, Datenmember public zu feklarieren, besser ist, sie private oder protected zu deklarieren und zugriffsroutinen bereitzustellen.

    Ferner ist "MyClass" ein sehr irreführender Name für ein Objekt. Eine Klasse so zu benennen ist durchaus legitim (auch wenn ein aussagekräftigerer Name durchaus wünschenswert wäre), aber Objekte des typs solltest du besser myObject oder schlimmstenfalls noch MyClassObject bzw. MyClassInstance nennen.

    Sollte es sich bei MyClass tatsächlich um eine Klasse handeln und nicht um ein Objekt, dann ist dein Code leider völliger Käse (nicht böse gemeint) und du solltest dir nochmal ein C++-Tutorial antun und noch ein wenig mehr lernen.

    Grüße

    Pumu



  • Mhh ja. War einerseits unglücklich von mir dargestellt, andererseits hab ich ->mysql wirklich public gesetzt *duck* 😉

    MyClass sollte besser MyClass* myObjekt heißen.
    mysql ist die public-Membervariable vom Typ MYSQL
    (das mit dem get und set war mir zuviel ölerei... steinigt mich, ich weiß. ich steinige auch immer die, die es so machen..)

    Was ich jetzt nur erwartet hatte, das ich mir erst den zeiger auf myObjekt->mysql holen muss um den dann zu überschreiben.

    Ich hab jetzt mal ein wenig rumpropiert und bin immer noch so schlau wie vorher 😞
    Ich kann zwar mit irgend einer Connection arbeiten, bekomme aber das original nicht wieder...
    Das was hinter Pointern steckt (Adresse von blablabla) ist mir schon bewusst und ich hatte bisher weder mit Zeigern noch mit Referenzen Probleme.

    nehmen wir mal an, ich würde zwei ints vertauschen wollen:

    int alt=4;
    int neu=5;
    int *tmp=*alt;
    *alt=&neu;
    //alt==5
    *alt=tmp;
    //alt==4
    

    sehe ich das so richtig?
    Wenn ja, wie bekomme ich das auf meine MYSQL Structs übertragen, ohne immer die Originalverbindung zu verlieren?



  • Du schreibst:

    -=]xXx[=- schrieb:

    ... Ich hab eine class MyClass, die eine Membervariable MYSQL mysql hat.

    MYSQL *original=&(MyClass->mysql);
    MYSQL neu;
    //neu initialisieren
    *(MyClass->mysql)=&(neu);
    //Funktionen aufrufen
    *(MyClass->mysql)=original;
    

    leider gehts so aber nicht :(...
    Was mache ich falsch? Wo liegt der Fehler?
    Klärt mich auf 😃

    mysql ist eine Struktur. Wenn Du diese temporär austauschen willst, musst Du Dir natürlich die ganze Struktur merken, um sie nachher wieder herstellen zu können; und nicht nur einen Pointer darauf.
    Also etwa so:

    MYSQL original = MyClass->mysql; // ganze struct merken
    MYSQL neu;
    //neu initialisieren
    MyClass->mysql = neu; // temporär überschreiben
    //Funktionen aufrufen
    MyClass->mysql = original; // wieder herstellen
    

    Gruß
    Werner



  • nehmen wirs mal Zeile für Zeile auseinander:

    int alt=4;
    int neu=5;
    

    alt und neu sind hier variablen vom typ int

    int *tmp=
    

    tmp ist ein pointer auf int

    *alt;
    

    Der (unäre) *-operator heißt Dereferenzerungsoperator, weil er den Verweis eines pointers auflöst. Er liefert also einen Wert vom Typ T zurück, wenn man ihn auf einen Pointer auf T anwendet. den *-operator auf eine normale Variable anzuwenden, die kein Pointer ist, ist nicht erlaubt. (Alt ist eine solche normale Variable) Man könnte das konstrukt *pT auch lesen als "das, worauf pT zeigt". Im ganzen soll deine Zeile vermutlich ausdrücken, dass der Pointer tmp auf alt zeigen soll. Dazu verwendet man de Adressperator &, der die Adresse des objektes zurückgibt, auf das er zeigt. In dem Falle also

    int* tmp = &alt
    
    *alt=&neu;
    

    hier versuchst du wieder den dereferenzierungsoperator anzuwenden auf etwas, was kein pointer ist (und was auch kein objekt ist, das den *-operator zur verfügung stellt). Außerdem holst du die Adresse von neu, obwohl du ja auf der linken Seite der gleichung keinen Pointer hast. Du willst vermutlich der variablen alt den Wert von neu zuweisen. Das ginge so:

    alt = neu;
    
    *alt=tmp;
    

    wie oben der Derefoperator falsch angewandt. Lässt du ihn weg, weist du allerdings der int-Variablen alt einen Pointer zu, wenn der Compiler das macht, dann wird er den Wert von tmp (die Adresse, die in Tmp gespeichert ist) in einen int umwandeln, und das willst du mit Sicherheit nicht.
    Hier wäre bei tmp der derefoperator angemessen, um den Wert zurückzubekommen, der an der Stelle gespeichertz ist, auf die tmp zeigt. Allerdings ist das immernoch der Speicherplatz von alt, deswegen weist du der variablen ihren eigenen Wert zu (nennt man Aliasing und ist ein Musterbeispiel für verschwendete CPU-power)
    Dass du alt in der zwischenzeit den Wert von neu zugewiesen hast, tut nix zur Sache, tmp zeigt ja nur auf den Speicher, und der kann zwischendrin beliebig geändert werden, ohne dass tp was davon merkt.

    Ums kurz zu machen: du hast offenbar noch ziemliche Schwierigkeiten im Verständnis von Pointern und dem Umgang mit ihnen. Evtl. solltest du dir doch noch mal ie entsprechenden Kapitel in einem beliebigen Einsteigerlehrbuch anschauen. (nicht böse gemeint)

    Gruß

    Pumu



  • Werner Salomon schrieb:

    mysql ist eine Struktur. Wenn Du diese temporär austauschen willst, musst Du Dir natürlich die ganze Struktur merken, um sie nachher wieder herstellen zu können; und nicht nur einen Pointer darauf.

    doch das geht:
    hier nun mal endlich eine (stark vereinfachte) moeglichkeit wie es gehen koennte:

    #include <iostream>
    using namespace std;
    
    struct MYSQL {
    	int data;
    	};
    
    class MyClass {
    	public:
    		MYSQL *mysql;
    		MyClass() : mysql(new MYSQL) {};
    		~MyClass() {delete mysql;};
    	};
    
    int main()
    	{
    	MYSQL *msql1,*msql2=new MYSQL();	//msql1=backup,msql2=neue MYSQL
    	MyClass *obj=new MyClass;
    
    	msql2->data=12;						//neue MYSQL struktur fuellen
    
    	obj->mysql->data=34;				//objekt fuellen
    	msql1=obj->mysql;					//MYSQL struktur in msql1 sichern
    	obj->mysql=msql2;					//struktur aus obj neu setzen
    
    	cout<<obj->mysql->data;				//ausgabe der 'neuen' struktur
    	obj->mysql=msql1;					//die alte wieder herstellen
    	delete msql2;						//die neue(nun wieder entfernte struktur) loeschen
    	cout<<obj->mysql->data;				//die 'alten' daten wieder ausgeben
    
    	return 0;
    	};
    

    @pumuckl: falls du sowas in der richtung geschrieben hast bitte ich um verzeihung-hab im moment nicht mehr den elan um mir das alles durchzulesen.

    die kommentar formulierungen sind glaub ich auch ungeschickt gewaehlt aber ich glaub es ist verstaendlich was gemeint ist 🤡



  • @pumuckel:
    das mit dem

    int *tmp=*alt;
    

    war ein vertipper...
    meinte das schon mit &alt.

    allerdings für ja

    alt=neu;
    

    nicht zu dem Ergebnis was ich möchte.
    ich will ja nicht (von meinem Verständnis her) alles was in neu steht in den Speicherbereich von alt kopieren, sondern sagen, das alt ab jetzt auf neu zeigen soll. das erreiche ich doch damit nicht.
    Und wenn ich auf tmp den derefoperator anwende, hab ich das gleiche. dann hätte ich mir ja nicht die Adresse sondern "nur" den wert merken müssen. Will ich ja aber nicht.
    Muss ich das dann so schreiben:

    &alt=tmp;
    

    ?

    Mit dem anderen Post setze ich mich erst morgen auseinander, muss jetzt ins Bettchen 😉
    n8

    PS: Mit Pointern hab ich keine Probleme, nur mit dem richtigen Operator 😉
    Ich will halt nur Adressen von Variablen (die keine Pointer sind) austauschen und die Werte (stucts) da lassen, wo sie im Speicher sind...



  • alt kann nicht auf neu zeigen, weil du alt als int deklariert hast und nicht als int*
    Eine normale Variable hat einen fest zugewiesenen Speicherbereich und kann nicht hin und her zeigen wie ein pointer.

    Wenn du der Variablen alt zwischenzeitlich einen anderen Wert zuweisen willst, musst du ihn irgendwoanders sichern, weil du ja den Speicherbereich von alt überschreibst.

    int alt = 4;
    int neu = 5;
     {   //neuer scope, damit du tmp nicht unnötig lange rumschleppst
    int tmp = alt; //einfach den Wert kopieren tmp ist jetzt 4
    alt = neu;  //alt ist jetzt 5
    //irgendwelchen Krempel mit alt anstellen
    alt = tmp;  //wieder auf 4 zurücksetzen
     } //ab hier gibts tmp nicht mehr
    

    eine andere Möglichkeit die dir evtl. gefällt:

    int alt = 4;
    int neu = 5;
    swap(alt, neu);   //alt <- 5, neu <- 4
    //irgendwas mit alt machen
    swap(alt, neu);   //alt <- 4, neu <- 5(falls alt zwischendrin nicht verändert wurde)
    

    Das Template swap aus der C++-Standardbibliothek vertauscht die Werte zweier Variablen/Objekte miteineander (bei objekten muss ein copy-ctor und ein zuweisungsoperator definiert sein)



  • ich war der meinung er wollte das ganze nur ueber pointer machen - also in etwa so:

    int *alt=new int,neu=5;
    *alt=4;
    int long=alt;    //sollte man sich nicht drauf verlassen-alternativ(und besser) einen pointer gleichen typs verwenden
    alt=&neu;       //alt ist jetzt 5
    

    -hab das ja auch so in meinem beispiel (weiter oben) implementiert



  • Das liegt dann also daran, das der Speicherbereich der Variablen fest im Programm einkompiliert ist... ich habs befürchtet... hab mich schon gewundert, das in keinem Tutorial über pointer sowas gemacht wird.
    Dann muss ich mir da was anderes zusammen frickeln... ich hab nämlich das gefühl, das so eine MySQL-Connection es nicht mag, wenn man sie hin und her kopiert... jedenfalls bekomme ich dann keine ergebnisse mit meinen Abfragen mehr 😞

    Vielen Dank für eure Geduld 🙂



  • -=]xXx[=- schrieb:

    Das liegt dann also daran, das der Speicherbereich der Variablen fest im Programm einkompiliert ist... ich habs befürchtet... hab mich schon gewundert, das in keinem Tutorial über pointer sowas gemacht wird.
    Dann muss ich mir da was anderes zusammen frickeln... ich hab nämlich das gefühl, das so eine MySQL-Connection es nicht mag, wenn man sie hin und her kopiert... jedenfalls bekomme ich dann keine ergebnisse mit meinen Abfragen mehr

    wie kommst du jetzt darauf? ich hab doch jetzt schon 2 funktionstuechtige wege aufgezeigt. da musst du dann auch nichts durch die gegend kopieren (ausser halt die zeiger - welche aber gewiss kleiner sind als deine MYSQL strukturen).
    der speicherbereich von variablen ist auch nicht fest im programm 'einkompiliert' sofern es zeiger sind, das ist es doch was gerade zeiger ausmacht.
    will jetzt auch nicht das thema noch laenger hinziehen, sondern nur darauf hinweisen dass es auch mit der anfaenglichen vermutung des fragestellers (das ganze ueber zeiger zu loesen) durchaus moeglich ist dieses problem zu loesen.



  • Cpt.Tanga schrieb:

    der speicherbereich von variablen ist auch nicht fest im programm 'einkompiliert' sofern es zeiger sind,

    Sind es aber nicht. davon rede ich doch die ganze zeit 😉
    Hab jetzt alles auf Zeiger umgebaut und nun läuft es auch so, wie ich mir das von anfang an vorgestellt hatte.


Anmelden zum Antworten