Den << Operator überladen



  • Wieso soll myendl ne Funktion sein? Dafür gibts doch enums.



  • Die Idee war es ähnlich wie bei den Standard Stream-Klassen zu machen. Und da ist endl nun mal gewöhnlich eine Funktion.



  • @Z2: und für welchen Nutzen?

    Greetz, Swordfish



  • Zu welchem Nutzen? Damit man soetwas:

    std::cout << std::endl;
    

    schreiben kann.



  • Guckst du mein Beispiel oben? Kann ich auch und brauche keine Funktion.
    War diese Klasse nicht, was der OP wollte? Siehst du darin einen Nachteil?

    Greetz, Swordfish



  • Ist ziemlich dicht an dem geforderten dran (abgesehen davon, daß du bei deinem endl noch explizit das Objekt vorher angeben mußt; was aber eigentlich auch egal ist).

    Unabhängig davon war meine Bemerkung an Michael E. gerichtet, der fragte, worum ich geschrieben habe, daß myendl eine Funktion sein soll.



  • Z2 schrieb:

    Zu welchem Nutzen? Damit man soetwas:

    std::cout << std::endl;
    

    schreiben kann.

    Dafür muss std::endl doch keine Funktion sein. Das geht auch, wenn man op<< für endl überlädt, wenn endl ein enum ist.

    Unabhängig davon war meine Bemerkung an Michael E. gerichtet, der fragte, worum ich geschrieben habe, daß myendl eine Funktion sein soll.

    Das hast du mir aber noch nicht hinreichend begründet. Dein einziges Argument ist, dass der Standard auch so verfährt. Nur wieso macht er das? Was bringt das? Oder ist das nur ne willkürliche Konvention?



  • Was weiß ich, warum der Standard es so macht wie er es macht? Aber im Standard funktioniert es und zwar auf sehr zufriedenstellende Weise. Und da wir hier die gleiche Aufgabenstellung haben, ist es doch erst mal die naheliegenste Lösung ihn zu kopieren, bevor man sich über andere Lösungen Gedanken macht, oder etwa nicht?

    Na gut, ich will mal versuchen zu argumentieren, welche Vorteile Funktionen an dieser Stelle haben, nämlich: Erweiterbarkeit. Wenn du einen zusätzlichen Manipulator brauchst, definierst du einfach eine zusätzliche Funktion ohne die ursprüngliche Klasse in irgendeiner Weise ändern zu müssen. Das geht mit allen anderen Lösungen nicht oder zumindest nicht so einfach.



  • Oh man, kaum ist man ein paar Stunden weg, schon ist der ganze Thread eine Seite länger. 😃

    @Swordfish: Keine schlechte Lösung, sie hat leider nur einen Harken, ich habe kein Editfeld in dem ich neue Zeilen mit \r\n erzeugen kann, sondern eine Liste. Um deine Lösung zu benutzen müsste ich bei jedem Aufruf des << Operators den String nach \r\n durchsuchen, und bei Bedarf den Teilstring flushen (was äußerst ineffizent wäre), oder sehe ich das falsch?

    @MichaelE: Hmm, ein Enum benutzten... Das wäre natürlich eine Möglichkeit, wenn ich dann den Code zum flushen in eine entsprechend überladene operator << Funktion einbaue. Werde ich auch mal ausprobieren. Am liebsten wäre mir aber, wie Z2 richtig vermutete, eine Funktion 🙂

    @Z2: Wie soll ich den String flushen, wenn myendl eine freie Funktion ist? Dann habe ich ja keinen Zugriff auf die Membervariabeln... (Es lässt sich kompelieren, wenn ich myendl eine freie Funktion ist)



  • Deine Klasse muß natürlich die entsprechenden Funktionen anbieten, die dann von den Manipulator-Funktionen (myendl und eventuell andere) aufgerufen werden. Im Zweifelsfall sieh dir einfach mal die Stream-Klassen der Standard-Library an. Daraus kann man sehr viel lernen (der Header <ostream> dürfte da ein guter Startpunkt sein).



  • Ok, ich habs hingekriegt, meine endgültig Lösung sieht jetzt so aus:

    //dbg.h
    class dbgObject
    {
        public:
            dbgObject();
            dbgObject& operator<<(std::string);
            dbgObject& operator<<(int zahl);
            dbgObject& Flush();
            dbgObject& operator<<(dbgObject& (*pf)(dbgObject&));
        private:
            HWND hwnd_dbgWnd_;
            std::string akt_zeile;
    };
    
    dbgObject& myendl(dbgObject& test);
    
    //dbg.cpp
    dbgObject& myendl(dbgObject& test)
    {
        test.Flush();
        return test;
    }
    dbgObject& dbgObject::operator<<(std::string text)
    {
        akt_zeile += text;
        return *this;
    }
    
    dbgObject& dbgObject::operator<<(int zahl)
    {
        std::stringstream text;
        text << zahl;
        return operator<<(text.str());
    }
    
    dbgObject& dbgObject::operator<<(dbgObject& (*pf)(dbgObject&))
    {
        return pf(*this);
    }
    
    dbgObject& dbgObject::Flush()
    {
        SendDlgItemMessage(hwnd_dbgWnd_,IDD_DBG_LIST, LB_ADDSTRING,0,(LPARAM) akt_zeile.c_str());
    
        //Nach unten scrollen
        if(autoscroll_)
            SendDlgItemMessage(hwnd_dbgWnd_,IDD_DBG_LIST,WM_VSCROLL,(WPARAM) SB_BOTTOM,0);
    
        akt_zeile = "";
        return *this;
    }
    
    //main.cpp
    int main()
    {
      dbgObject dbg;
      ...
      dbg << "bla" << " bla " << 4 << myendl;
      ...
      return 0;
    }
    

    Eine letzte Frage habe ich noch: Woher kriegt die freie Funktion myendl ihren Parameter &dbgObject und warum muss ich nicht schreiben dbg << myendl() ???



  • Z2 schrieb:

    Na gut, ich will mal versuchen zu argumentieren, welche Vorteile Funktionen an dieser Stelle haben, nämlich: Erweiterbarkeit. Wenn du einen zusätzlichen Manipulator brauchst, definierst du einfach eine zusätzliche Funktion ohne die ursprüngliche Klasse in irgendeiner Weise ändern zu müssen. Das geht mit allen anderen Lösungen nicht oder zumindest nicht so einfach.

    Das geht mit enums genauso einfach. Nur braucht man dafür nen Template-"Trick", die im Standard ja wirklich rar gesät sind. Das könnte eine Erklärung sein.



  • flammenvogel schrieb:

    Eine letzte Frage habe ich noch: Woher kriegt die freie Funktion myendl ihren Parameter &dbgObject und warum muss ich nicht schreiben dbg << myendl() ???

    Du übergibst nur einen Funktionszeiger und hier

    dbgObject& dbgObject::operator<<(dbgObject& (*pf)(dbgObject&))
    {
        return pf(*this); // pf ist ein Funktionszeiger
    }
    

    wird die Funktion dann aufgerufen.



  • ok, jetzt versteh ichs

    thk


Anmelden zum Antworten