Funktion löscht Membervariable einer Klasse
-
Hallo zusammen,
ich bin neu hier im Forum, und auch relativ neu in C++. Ich bin gerade dabei für meine Diplomarbeit ein Programm zu schreiben. Nachdem ich nun einige Hürden genommen habe sitze ich seit einigen Tagen an einem Problem, das ich mithilfe von Google etc. nicht lösen konnte:
Ich habe eine Klasse A, von der in main() eine Instanz 'InstanzA' erstellt wird. Diese Klasse besitzt eine Membervariable
class A { public: vector<double> Werte; };Zusätzlich habe ich eine Klasse B mit der Funktion Run():
class B { public: void Run(A obj); };die als Argument ein Objekt der Klasse A nimmt und dem Membervektor von A verschiedene Werte zuweist. Zum Beispiel
void Run(A obj) { obj.Werte[1]=550; }Wenn ich nun folgende main laufen lasse:
void main() { A InstanzA; B InstanzB; InstanzB.Run ( InstanzA ); cout << InstanzA.Werte[1]; }gibt er mir eine null zurück! Der 'Fehler' löscht also den Vektor, sobald die Funktion abgeschlossen ist und in main() zurückkehrt.
Wahrscheinlich habe ich etwas nicht verstanden, bzw. wende die Konzepte falsch an. Daher wäre ich sehr dankbar, wenn mir jemand auf die Sprünge helfen könnte!
Vielen Dank im Voraus,
Tad
-
1. Es heißt int main, nicht void main
2. Ja, du hast da etwas falsch verstanden. In dem Moment in dem du das Objekt übergibst, wird eine Kopie erstellt. Die Werte der Kopie werden verändert, nicht die des eigentlichen Objekts. Du möchtest ein Alias für dein Objekt in main erstellen, das macht man mit Referenzen:void foo(int i) { i = 5; } void bar(int& i) { i = 7; } int main() { int i = 3; foo(i); // i = 3, da nur kopiert bar(i); // i = 7 }
-
Hi!
Danke für die Antwort!! Das war ja unglaublich schnell!!
Ich hab es jetzt als Referenz übergeben und jetzt funktioniert es
Wusste schon, dass man es eigentlich so macht - allerdings war ich mir generell unsicher ganze Objekte zu übergeben 
Vielen Dank nochmal!!
-
Du übergibst eine Kopie deiner Klasse A an B::Run(). In der Funktion wird dann die Kopie geändert, aber wenn die Funktion zuende ist, dann ist auch die Lebensdauer der Kopie beendet. Ein paar gute Googlestichwörter dazu sind call by value und call by reference. Referenz ist auch das Stichwort zur Lösung:
class B { public: void Run(A &obj); };void B::Run(A &obj) // Hier hattest du das B:: vergessen. Tippfehler? Falls es so war und sich trotzdem ein Programm erstellen lies, dann hast du noch was ganz anderes falsch gemacht! { obj.Werte[1]=550; }obj ist nun eine Referenz, ein Verweis, auf das Funktionsargument, keine Kopie mehr. Die Änderungen betreffen also direkt das Objekt welches beim Funktionsaufruf angegeben wurde.
Ich habe das Thema hier sehr knapp dargestellt, es gibt noch viel mehr dazu zu wissen. Zum Beispiel, wann man die Referenzen einsetzt, obwohl man das Objekt gar nicht ändern möchte, welche Alternativen es gibt und wie man ein konstantes Objekt an eine Referenz binden kann. Und neuerdings (C++11) sogar, wie man rvalues an Referenzen binden kann. Siehe meine Signatur für Buchtipps.
P.S.: Außerdem enthält in deinem Beispiel der vector in A überhaupt keine Objekte, dein Zugriff auf das zweite Element (dir ist klar, dass das erste Element bei 0 wäre?) ist daher undefiniert.
edit:
Tad schrieb:
Danke für die Antwort!! Das war ja unglaublich schnell!!
Allerdings. Naja, dann hast du die Antwort eben doppelt.
-
Wenn ich raten müsste, würde ich sagen, Du hast während des Studiums Java gelernt hast und Dir ist bis jetzt nicht aufgefallen, dass C++ einem keine Indirektion aufzwinkt. Während in Java eine Variable eines Klassentyps in Wirklichkeit ein Zeiger ist, den man "Referenz" in Java nennt, ist in C++ eine Variable eines Klassentyps das Objekt selbst, welches bei Aktionen wie
A obj1; A obj2 = obj1;selbst kopiert wird, statt dass nur eine "Referenz" kopiert wird, die sich dann auf dasselbe Objekt bezieht. Willst Du einen Zeiger, musst du dies explizit sagen. Allerdings soll das jetzt kein Grund sein, Objekte in C++ wild im Freispeicher anzulegen und mit rohen Zeigern zu hantieren. Um Resourcen-Lecks (inklusive Speicherlecks) zu vermeiden, ordnen wir eine Resource einem "Besitzer" zu. Das ist ein Objekt, welches sich um die Verwaltung kümmert. std::vector ist so ein Beispiel, welches seine Elemente selbstständig verwaltet, ohne dass Du hier ein new[] oder ein delete[] benötigen würdest. Das ist eine ziemlich elegante Sache, die Du verstehen, schätzen und ausnutzen solltest.
Tad schrieb:
obj.Werte[1]=550;So befüllt man auch keinen leeren Vektor! Siehe resize bzw. push_back.
-
Hey!
Was ist der genaue Grund dass ich den vector nicht folgendermaßen befüllen kann
obj.Werte.resize(2); obj.Werte[0]=550; obj.Werte[1]=555;?
-
Tad schrieb:
Was ist der genaue Grund dass ich den vector nicht folgendermaßen befüllen kann
So geht das schon (ein bisschen umständlich, aber egal). Bei deinem bisherigen Code war da jedoch nirgendwo ein resize zu sehen.
-
Tad schrieb:
Was ist der genaue Grund dass ich den vector nicht folgendermaßen befüllen kann
obj.Werte.resize(2); obj.Werte[0]=550; obj.Werte[1]=555;?
Die Frage ergibt keinen Sinn, da der Vektor "obj.Werte" so erwartungsgemäß mit den Werten 550 und 555 gefüllt wird. Möglicherweise ist aber "obj.Werte" gar nicht der Vektor, den Du befüllen willst. Ich habe nämlich immer noch das Gefühl, dass Du in Deinem Programm da einen einzigen Vektor vermutest, wo tatsächlich mindestens zwei hinter stecken. Du hättest dann durch eine andere Dir bekannte Sprache eine gewisse Erwartungshaltung, die nicht richtig ist, weil C++ anders funktioniert als Du denkst.