Pointer-Problem mit Basisklasse und Übergabe an Methode
-
Eisflamme schrieb:
(oder schmeiß das Buch weg, wenn es von Jürgen Wolf ist).

-
Erstmal danke für die Antworten.
Eisflamme schrieb:
(oder schmeiß das Buch weg, wenn es von Jürgen Wolf ist).
Das Buch, das ich benutze, ist von Helmut Erlenkötter

Eisflamme schrieb:
Überhaupt ist der ganze Sinn hinter Deinem Programm strittig.
Das ist ja auch nur der Teil eines Programms.
Hier der geänderte Quelltext:
#include <iostream> using namespace std; class Basisklasse { private: int a; int b; public: int wert1; int wert2; public: Basisklasse(); void tuWas(Basisklasse *pBasis1, Basisklasse *pBasis2); }; Basisklasse::Basisklasse() { wert1 = 1; wert2 = 2; } void Basisklasse::tuWas(Basisklasse *pBasis1, Basisklasse *pBasis2) { // Hier wird was Tolles gemacht } int main() { Basisklasse b; // *** Hier kommt nun das Problem *** b.tuWas(b.wert1, b.wert2); }Fehler kommt nach wie vor, aber da lese ich erstmal noch mal das Kapitel über Pointer und Klassen.
-
Ja, b.wert1 ist ja auch ein int und keine Basisklasse. Und Du brauchst da eigentlich auch überhaupt keine Parameter übergeben. Wenn Du von einem Klassenobjekt eine Methode aufrufst, sind in der Methode sämtliche Attribute eben dieser Klasseninstanz bereits bekannt.
#include <iostream> using namespace std; class Basisklasse { private: int a; int b; // Attribute sollten in Klassen auch immer private sein, aber gut public: Basisklasse(int a, int b) : a(a), b(b) {} void tuWas(); }; void Basisklasse::tuWas() { cout << "a ist " << a << " und b ist " << b << "."; } int main() { Basisklasse einObjekt(10, 20); einObjekt.tuWas(); return 0; }
-
Ok, so, wie du es geschrieben hast, leuchtet es mir auch ein und macht ja auch Sinn. Mal kurz zum Hintergrund: Das von mir angesprochene Beispiel ist für eine Programmieraufgabe (natürlich nicht in so einfacher Form, das war nur, damit das Problem klar wird), und da wird gefordert, dass die Pointer genutzt werden (auch wenn es noch so merkwürdig und unlogisch ist).
-
imac2011 schrieb:
Ok, so, wie du es geschrieben hast, leuchtet es mir auch ein und macht ja auch Sinn. Mal kurz zum Hintergrund: Das von mir angesprochene Beispiel ist für eine Programmieraufgabe (natürlich nicht in so einfacher Form, das war nur, damit das Problem klar wird), und da wird gefordert, dass die Pointer genutzt werden (auch wenn es noch so merkwürdig und unlogisch ist).
nein es ist nicht unlogisch, für lernzwecke ist sowas ja vollkommen ok. aber du versuchst eine kuh dahin zu geben wo ein auto erwartet wird(int <---> zeiger auf eine klasse)
-
Aber mal rein zum Verständnis: Wenn ich folgenden Code habe
Basisklasse *pB; pB = &b.wert1;und b.wert1 im Konstruktor den Wert 1 zugewiesen bekommt, dann weise ich dem Zeiger pB doch im obigen Beispiel nur die Adresse von b.wert1 zu oder nicht? Und diese müsste ich doch auch an einen andere Zeiger übergeben können.
-
Du hast es scheinbar immer noch nicht verstanden.
Deine Typen passen doch nicht.
pB ist ein Zeiger auf Basisklasse, &b.wert1 liefert dir einen Zeiger auf int. Die kannst du nicht zuweisen, die Typen müssen schon stimmen.
-
Braunstein schrieb:
Du hast es scheinbar immer noch nicht verstanden.
Deine Typen passen doch nicht.
pB ist ein Zeiger auf Basisklasse, &b.wert1 liefert dir einen Zeiger auf int. Die kannst du nicht zuweisen, die Typen müssen schon stimmen.Ja, dass die Typen nicht passen, habe ich nun verstanden, steht ja auch in der Fehlermeldung. Was ich aber nicht verstanden habe ist, wie ich das nun gelöst bekomme, den Wert an den Zeiger der Basisklasse zu übergeben. Dies ist ja ohne Weiteres nicht möglich, bedingt durch die angesprochene Typeninkompatibilität.
-
imac2011 schrieb:
Ja, dass die Typen nicht passen, habe ich nun verstanden, steht ja auch in der Fehlermeldung. Was ich aber nicht verstanden habe ist, wie ich das nun gelöst bekomme,...
In dem du auch etwas entsprechendes übergibst;
Basisklasse b; Basisklasse *pB; pB = &b.wert1; // Unsinn pB = &b; // Besser // Über den Zeiger kannst du ja auf die Werte zugreifen: int wert = pB->wert1;
-
Soo, hab das Ganze nun so gelöst, und so funktioniert es auch. Gibt es noch Anregungen eurerseits zu dem folgenden Quellcode?
#include <iostream> using namespace std; class Basisklasse { public: int wert1; int wert2; public: Basisklasse(); void tuWas(Basisklasse *pBasis1, Basisklasse *pBasis2); }; Basisklasse::Basisklasse() { wert1 = 1; wert2 = 2; } void Basisklasse::tuWas(Basisklasse *pBasis1, Basisklasse *pBasis2) { Basisklasse bX; Basisklasse bY; pBasis1 = &bX; pBasis2 = &bY; int a = pBasis1->wert1; int b = pBasis2->wert2; cout << a<< " + " << b<< endl; } int main() { Basisklasse b; Basisklasse *pWert1; Basisklasse *pWert2; pWert1->wert1; pWert2->wert2; b.tuWas(pWert1,pWert2); }Ansonsten vielen Dank für die schnelle Hilfe!!!!!!!!

-
imac2011 schrieb:
Soo, hab das Ganze nun so gelöst, und so funktioniert es auch. Gibt es noch Anregungen eurerseits zu dem folgenden Quellcode?
Das er Fehlerhaft ist, und eigentlich gnadenlos abschmieren sollte. Zudem scheinst du Zeiger nicht verstanden zu haben, und unnötige Kopien anzulegen.
Du übergibst (uninitialisiere) Zeiger, dereferenzierst diese, und weist das Ergebnis lokalen Variablen zu.
Ich glaube eher du willst so etwas (Auch wenn es weiterhin unsinnig ist):
void Basisklasse::tuWas( Basisklasse *p) { // Da Zeiger können null sein können, auch behandeln. if(!p) return; // Über den Zeiger die Werte ausgeben cout << p->a << " + " << p->b<< endl; } int main() { Basisklasse b; b.tuWas(&b); }
-
asc schrieb:
Das er Fehlerhaft ist, und eigentlich gnadenlos abschmieren sollte. Zudem scheinst du Zeiger nicht verstanden zu haben, und unnötige Kopien anzulegen.
Du übergibst (uninitialisiere) Zeiger, dereferenzierst diese, und weist das Ergebnis lokalen Variablen zu.
Ich glaube eher du willst so etwas (Auch wenn es weiterhin unsinnig ist):
Eigentlich will ich glaube ich mehr sowas:
#include <iostream> using namespace std; class Basisklasse { public: int wert1; int wert2; public: Basisklasse(); void tuWas(Basisklasse *pBasis1, Basisklasse *pBasis2); }; Basisklasse::Basisklasse() { wert1 = 1; wert2 = 2; } void Basisklasse::tuWas(Basisklasse *pBasis1, Basisklasse *pBasis2) { int a = pBasis1->wert1; int b = pBasis2->wert2; cout << a << " + " << b << endl; } int main() { Basisklasse b; b.tuWas(&b,&b); }Aber wahrscheinlich hast du recht, das Prinzip der Zeiger muss ich echt noch ein paar mal lesen... und dann noch mal lesen ... und dann noch mal lesen.
-
imac2011 schrieb:
Eigentlich will ich glaube ich mehr sowas:
//... void Basisklasse::tuWas(Basisklasse *pBasis1, Basisklasse *pBasis2) { int a = pBasis1->wert1; int b = pBasis2->wert2; cout << a << " + " << b << endl; } //...Auch hier hast du das Problem das Zeiger den Wert NULL/0 annehmen können (womit man Zeiger, denen man nicht direkt einen gültigen Wert zuweist, immer initialisieren sollte). Wenn ich deine Methode wie folgt verwende, solltest du eine Zugriffsverletzung bekommen:
int main() { Basisklasse b; b.tuWas(0,0); }Davon abgesehen wundert es mich, wie verschwenderisch du mit Leerzeilen umgehst, aber anderseits bei der Klammersetzung die kompakte Schreibweise vorziehst (was reine Geschmackssache ist, aber man einheitlich machen sollte). Für ein Forum solltest du zumindest die Leerzeilen auf die sinnvollen reduzieren (Damit andere den Code besser überblicken können).
-
Sein letzter Code ist doch in Ordnung. Dass Nullzeiger übergeben werden können, ja gut. Darf man halt einfach nicht machen (dann wären Referenzen besser, aber egal).
Also bei Zeigern gibt es nicht viel zu verstehen. Die speichern einfach nur eine Adresse auf irgendeine andere Variable (wobei ein Klassenobjekt auch eine Variable ist). Prinzipiell haben Adressen ja das gleiche Format, weswegen man theoretisch überlegen könnte einfach nur einen speziellen Typ "Zeiger" zu nutzen.
Doch in C++ gibt es dann auch noch Typsicherheit bei so was. Das bedeutet, Du gibst auch an, auf was ein Zeiger zeigen muss.
TypAufDenDerZeigerZeigt* zeiger;Jetzt kannst Du in
zeigerAdressen von Objekten speichern mit der Einschränkung, dass diese Objekte vom TypTypAufDenDerZeigerZeigtsein muss.Zeiger nutzt man in C++ in deinem Zusammenhang (gibt noch andere), um call by reference umzusetzen. Würdest Du dein Objekt ohne Zeiger übergeben, würde nämlich call by value umgesetzt werden, d.h. das gesamte Objekte würde kopiert werden. Für Deine Anzeige macht das praktisch keinen Unterschied in der Ausgabe, aber die Kopie ist aufwendiger zu sagen "Ich habe die Baupläne für das Objekt mitgebracht, ich baue es Mal kurz auf" als nur kurz zu sagen "Hey, das Objekt, das ich meine, steht da hinten".
Der große Unterschied ist sonst, dass Du bei Zeigerübergabe beim Ändern von Werten der Objekte auch das Objekt in der main änderst (ist ja das gleiche, wir haben ja nur die Position mitegeteilt). Wenn Du es call by value übergibst, ist das ein neues Objekt. Wenn Du z.B. einen Baum kopierst und in Deiner Funktion einen Ast absägst, ist der Baum in der main unversehrt.
Und wenn jetzt eine Funktion erwartet, dass Du ihr "zeigst", wo ein Baum (Basisklasse) steht, dann kannst Du ihr nicht sagen, wo ein Ast (int) ist, denn das will die Funktion nicht haben. Sie ruft die Polizei (Compiler) und lässt den Positions-Angeber (Programmierer, hier OP) standrechtlich erschießen.
Daher: Immer auf die Typen achten, auch bei Zeigern!
-
Ok, das mit den Leerzeilen nehme ich mir mal fürs Forum zu Herzen, aber ansonsten schreibt es sich so (für meine persönliche Meinung) besser.
Danke für ausführliche Erklärung. Ich werde nun mal probieren, das Ganze auf meine Aufgabe umzusetzen.