Ausgeben von Referenzen über std::cout
-
Vielen Dank! Hatte ich fast befürchtet!
Was ist denn das Vorgehen, wenn ich prüfen möchte, ob das Objekt, das durch die Referenz repräsentiert wird das gleich ist, wie z.B. in der aufrufenden Methode? Gebe ich dann die Adresse der Referenz aus (also im Bsp. &myClass)?
Hintergrund ist, dass ich aufgrund von Refactoring nun Referenzvariablen in einer abstrakten Basisklasse habe, die beim Aufruf des Konstrukturs der abgeleiteten Klasse initialiisert werden (der Konstruktor der abgleiteten Klasse erhält 2 Referenzparameter und übergibt die dem Konstruktor der Basisklasse). Die Referenzvariablen der Basisklasse sind protected, so dass ich davon ausgehe, dass sie in Methoden der abgleiteten Klasse mit den im Konstruktor übergebenen Werten zur Verfügung stehen. Nun will ich prüfen, ob hier mein Denkfehler liegt und nun in der Basisklasse Referenzen auf die Referenz bestehen!
-
Reth schrieb:
Was ist denn das Vorgehen, wenn ich prüfen möchte, ob das Objekt, das durch die Referenz repräsentiert wird das gleich ist, wie z.B. in der aufrufenden Methode? Gebe ich dann die Adresse der Referenz aus (also im Bsp. &myClass)?
Nachdem, was ich gelesen habe, heißt gleich für dich, gleicher Speicherbereich.
Leider muss das bei Mehrfachvererbung (ich weiß nicht ob anders auch) nicht
zwangsläufig der Fall sein:#include <iostream> #include <string> class A{ int i; }; class B{ int j; }; class C : public A, public B{}; int main() { C c; A& aRef = c; B& bRef = c; C& cRef = c; std::cout << &aRef << std::endl; std::cout << &bRef << std::endl; std::cout << &cRef << std::endl; }0xbffff9cc
0xbffff9d0
0xbffff9ccDu kannst sogar Beispiele konstruieren, wo eine Referenz des gleichen Typs nicht
zwangsläufig die gleiche Adresse hat, weil ein Objekt doppelt davon erbt.#include <iostream> #include <string> class A{ int i; }; class B : public A{ }; class C : public A{ }; class D : public B, public C{}; int main() { D d; C& cRef = d; B& bRef = d; A& a1Ref = cRef; A& a2Ref = bRef; std::cout << &a1Ref << std::endl; std::cout << &a2Ref << std::endl; }0xbffff9cc
0xbffff9c8Falls du allerdings immer(!!!) virtuell (oder nicht doppelt) von dieser Klasse erbst, kriegst du
(glaub ich) immer die gleiche Speicheradresse bei Verwendung einer Referenz
auf diese virtuell geerbte Klasse.#include <iostream> #include <string> class A{ int i; }; class B : virtual public A{ }; class C : virtual public A{ }; class D : public B, public C{}; int main() { D d; C& cRef = d; B& bRef = d; A& a1Ref = cRef; A& a2Ref = bRef; std::cout << &a1Ref << std::endl; std::cout << &a2Ref << std::endl; }0xbffff9cc
0xbffff9ccBei einfachen Vererbungsketten (keine Mehrfachvererbung) brauchen die
Typen der Referenzen (bei vermutlich vielen Compilern) nichtmal gleich sein.#include <iostream> #include <string> class A{ int i; }; class B : public A{ int j; }; class C : public B{ int k; }; int main() { C c; A& aRef = c; B& bRef = c; C& cRef = c; std::cout << &aRef << std::endl; std::cout << &bRef << std::endl; std::cout << &cRef << std::endl; }0xbffff9c8
0xbffff9c8
0xbffff9c8Zu debug-Zwecken reicht aber eine einfache Ausgabe der Speicheradresse auf
gleichen Referenztypen basierend, häufig aus.Bevor jetzt Beschwerden kommen, dass der Standard das aber nicht garantiert:
-> Es sind nur praktische Hinweise, die wohl (vermutlich) auf einen Großteil
der Compiler zutreffenGruß,
CSpille
-
Gibt es denn dann in C++ eine einfache Möglichkeit, so eine Gleichheit zu prüfen bzw. über Ausgaben im Debugmodus nach zu vollziehen?
Unter Java ist dies sehr einfach, man gibt einfach das Objekt selbst aus, dann wird automatisch dessen eindeutige ID rausgeschrieben:
// Pseudocode ... MyObject o1 = new MyObject(); System.out.println(o1);
-
Gib der klasse eine statische ID, zähl die bei den Konstruktoren hoch, speicher den jeweiligen Wert im Objekt. Fertig. Darfst natürlich Kopierkonstruktor und Zuweisungoperatoren etc nicht vergessen.
-
Reth schrieb:
mal eine naive Frage: Warum kann ich denn keine Referenz auf eigene Objekte direkt über std::out ausgeben?
Das hängt damit zusammen, daß wenn Du eine Referenz aufrufst, sich das ganze so verhält, als hättest Du den Wert direkt aufgerufen:
MyObject o; cout << o; // Geht logischerweise nicht. MyObject &r = o; cout << r; // Das gleiche in grün, deshalb geht es auch nicht.Um es mal mit Zeigern zu vergleichen:
MyObject *p = &o; cout << p; // Geht natürlich, weil er nur eine Adresse ausgibt. // Aber: cout << r; // würde eher dem Aufruf cout << *p; // entsprechen, was wiederum cout << o; // entspricht. // Und daß das nicht geht, dürfte einleuchten.Alles klar?
-
Denke schon.
Nach meinem Verständnis eurer Antworten geht das deshalb nicht, weil ostream bzw. der <<-Operator nicht wissen, wie sie mit dem Wert eines Objektes (also nicht seiner Speicheradresse) umgehen sollen.
Daher auch der Hinweis von daersc, dass man den Operator überladen müsste.
Dieses Überladen würde man dann in seiner eigenen Klasse machen, oder?
-
Reth schrieb:
Dieses Überladen würde man dann in seiner eigenen Klasse machen, oder?
Entweder in der Klasse selbst oder als globale Funktion.
-
Reth schrieb:
Dieses Überladen würde man dann in seiner eigenen Klasse machen, oder?
Nein, das muss man in einer freien Funktion machen, denn es wäre ja wenn überhaupt eine Klassenmethode eine Methode von std::ostream und da kommst du nicht ran. Daher als freie Funktion. Siehe auch hier:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-232010.html
-
Reth schrieb:
Dieses Überladen würde man dann in seiner eigenen Klasse machen, oder?
Nein, der überladene Operator gehört ja zu ostream und nicht zu deiner Klasse.
Da man nicht im ostream-Header herumbasteln darf/sollte, definiert man ihn als globale Funktion.Edit: könnte schwören, dass SeppJ's Beitrag zehn Sekunden vor dem Absenden noch nicht da war.
-
Wobei ich hier schon öfter das Vorgehen "freie Funktion ruft public Memberfunktion auf" gesehen habe. So in der Art
class myClass { // ... säckeweise private-Member... public: virtual ostream& print(ostream&) const; // hat Zugriff auf Obige und wird weitervererbt }; ostream& operator<<(ostream& ost, myClass const& m) { return m.print(ost); }Gruß,
Simon2.
-
Athar schrieb:
Edit: könnte schwören, dass SeppJ's Beitrag zehn Sekunden vor dem Absenden noch nicht da war.
Dann würde ich mich aber mal bei deinem Internet Provider beschweren,
wenn das Senden ca. 1,5 Minuten dauert
Mein Ping braucht ja schon fast 400ms, aber das ist schon etwas sehr heftig
