Ausgeben von Referenzen über std::cout



  • 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
    0xbffff9cc

    Du 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
    0xbffff9c8

    Falls 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
    0xbffff9cc

    Bei 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
    0xbffff9c8

    Zu 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 zutreffen

    Gruß,
    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?



  • @NES-Spieler:

    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.


  • Mod

    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 😃


Anmelden zum Antworten