wie funktioniert equal()



  • Analog zum Einlesen mittels >> einen Ausgabe-Operator << definieren:

    ostream& operator<<(ostream& out, const dataset& parameter)
    


  • Progressive schrieb:

    manni66 schrieb:

    Progressive schrieb:

    Wenn man einen String definiert, dann ist das Ende doch vorgegeben. Warum wird z.B. "string str = "Content"; nicht ein entsprechendes Zeichen nach dem String-Inhalt gesetzt ?

    Woher weiß equal, dass es ein String ist?
    Woher weiß equal, welches Zeichen am Ende steht?
    Welches Zeichen soll einen std::vector<int> beenden?
    Welches Zeichen soll einen std::vector<Foo> beenden?

    Weil es als solches definiert wurde ?

    Du übergibst keinen String sondern einen Iterator.



  • Th69 schrieb:

    Analog zum Einlesen mittels >> einen Ausgabe-Operator << definieren:

    ostream& operator<<(ostream& out, const dataset& parameter)
    

    Hi, habe in der Zwischenzeit generell mich mal etwas über C++ eingelesen. Leider traf ich nie auf den o.a. Fall bzw. konnte ihn darauf abstrahieren.

    Was bedeutet denn ostream& operator<<(ostream& out, const dataset& parameter) ?
    Bei http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt steht std::basic_ostream::operator<< Inserts data into the stream.

    Wo/wie wirkt denn out ? Meinem Verständnis nach habe ich bislang zwei streams: Jeweils einen für die Dateieinlese und einen für die Dateiauslese (in meinem Beispiel database und output). Was macht daher out und in bzw. was macht der operator konkret ?

    Und was ist "parameter" ? Definiert wurde es ja glaube als Variable vom Typ dataset. Aber warum ?



  • Wie kommt es, daß du den Eingabe-Operator >> verwendest (und zu verstehen scheinst), aber den gegenteiligen Ausgabe-Operator << nicht?

    Stichwort: Überladung von I/O Stream Operatoren, s. z.B. Overloading the I/O operators

    PS: Im Thread Ausgabe von Objekten mittels for-Schleife und Methoden gibt es auch eine Erklärung zum <<-Operator (von "HarteWare").



  • Th69 schrieb:

    Wie kommt es, daß du den Eingabe-Operator >> verwendest (und zu verstehen scheinst), aber den gegenteiligen Ausgabe-Operator << nicht?

    Weil ich den dato lediglich analog definiert habe. Ich bin eher jemand, bei dem das Verständnis mit dem Ausprobieren kommt. Aber an den Punkt gelange ich bzgl. diesen streams bislang nicht (da man da im Vorfeld scheinbar doch mehr verstanden haben muss ^^). Ohne Klasse u.ä. lediglich Dateien einzulesen usw. ist klar, aber da kommt man ja auch ohne den <<operator aus.

    Th69 schrieb:

    Stichwort: Überladung von I/O Stream Operatoren, s. z.B. Overloading the I/O operators

    PS: Im Thread Ausgabe von Objekten mittels for-Schleife und Methoden gibt es auch eine Erklärung zum <<-Operator (von "HarteWare").

    Danke für die Links! Das hat mir vom Verständnis schonmal geholfen, ich probiere das mal umzusetzen 🙂



  • So, habe jetzt alles und es funktioniert sogar.
    Verstehe es aber trotzdem nicht 😃 🙄

    Ich habe Folgendes:

    //main.cpp

    #include <fstream>
    #include <iostream>
    #include <string>
    #include <limits>
    #include <vector>
    #include <algorithm>
    #include "APD.h"
    
    using namespace std;
    
    int main(int argc,char *argv[])
    {   
    const char *INPUTFILE="Test.txt"; 
    ifstream input(INPUTFILE);
    APD apd(input);
    apd.print();
    }
    

    //APD.h

    #ifndef APD_H
    #define APD_H
    #include <iostream>
    
    class APD
    {
    	private:
    		int m_SN;
    		double m_temperature;
    		int m_rad;
    		int m_grid;
    		int m_grid_pos;
    		double m_M;
    		double m_UBias;
    		double m_Id;
    		double m_dM;
    
    	public:
    		ostream& operator<<(ostream& out);	
    		friend istream& operator>> (istream& in, APD& apd);						
    
    		APD();	
    		APD(ifstream& input);										
    
    		~APD();	
    };
    #endif
    

    //APD.cpp

    #include <string>
    #include <limits>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    #include <fstream>
    #include "APD.h"
    
    using namespace std;
    
    	APD::APD()
    	{
    		m_SN=0.; 
    		m_temperature=0; 
    		m_rad=0.; 
    		m_grid=0.; 
    		m_grid_pos=0.; 
    		m_M=0; 
    		m_UBias=0; 
    		m_Id=0; 
    		m_dM=0;
    	}
    
    	APD::~APD(){}	
    
    	APD::APD(ifstream& input)										
    	{
    		while(!input.eof()) 
    		{			
    			if(isdigit(input.peek()))							
    			{
    				break;					
    			}		
    			else input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');			
    		}
    		input >> m_SN >> m_temperature >> m_rad >> m_grid >> m_grid_pos >> m_M >> m_UBias >> m_Id >> m_dM;
    	}
    
    	istream& operator>> (istream& in, APD& apd)		
    	{     
    		while(in) 
    		{			
    			if(isdigit(in.peek()))								
    			{
    				break;					
    			}		
    			else in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');			
    		}
    		in >> apd.m_SN >> apd.m_temperature >> apd.m_rad >> apd.m_grid >> apd.m_grid_pos >> apd.m_M >> apd.m_UBias >> apd.m_Id >> apd.m_dM;	
    		return in;
    	}
    
    	ostream& APD::operator<<(ostream& out) 							
    	{     
    		out << m_SN << m_temperature << m_rad << m_grid << m_grid_pos << m_M << m_UBias << m_Id << m_dM;	
    		return out;
    	}						
    
    	void APD::print() const
    	{
    		cout<<"*************************************"<<endl;
    		cout<<"SN	: "<<m_SN<<endl;
    		cout<<"Grid	: "<<m_grid<<endl;
    		cout<<"Grid Pos	: "<<m_grid_pos<<endl;
    		cout<<"*************************************"<<endl;
    	}
    

    Ich verstehe nicht, wofür ich ostream& operator<<(ostream& out) und friend istream& operator>> (istream& in, APD& apd) benötige.



  • Progressive schrieb:

    So, habe jetzt alles und es funktioniert sogar.
    Verstehe es aber trotzdem nicht 😃 🙄

    [...]

    Ich verstehe nicht, wofür ich ostream& operator<<(ostream& out) und friend istream& operator>> (istream& in, APD& apd) benötige.

    Also: Deine print-Funktion gibt immer auf der Standardausgabe Daten aus ( cout << ... ). Normalerweise möchte man sowas allgemein halten, dass man auch zum Beispiel in eine Datei schreiben könnte. Du kannst deinem print also einen Parameter vom Typ ostream& spendieren und statt cout den übergebenen Stream verwenden.

    Den opereator<< brauchst du, damit du in deinem Hauptprogramm sowas schreiben kannst:

    APD apd(input);
    // statt: apd.print();
    std::cout << apd << '\n';
    

    Dazu definiere den operator<< analog zu operator>>, also NICHT so wie du es gemacht hast, sondern definiere ihn analog AUSSERHALB der Klasse und gib ihm ostream& und const APD& als Parameter. Darin schreibst du dann mit << auf den ostream, den du am Ende returnst. Oder besser, rufe in dem operator<< einfach apd.print(os) auf, nachdem du dem print das ostream-Argument hinzugefügt hast.



  • Ok, danke!
    Warum soll ich die <<,>> Operatoren denn außerhalb der Klasse definieren bzw. wo denn ? In main ?

    Mit analog meinst du:

    ostream& operator<<(ostream& out, const APD&);	
    istream& operator>>(istream& in, const APD&);
    

    oder

    ostream& operator<<(ostream& out, APD& apd);	
    istream& operator>>(istream& in, APD& apd);
    

    ?

    Ich verstehe den zweiten Parameter irgendwie nicht. Was bedeutet "APD&" und was "APD& apd" ? Ich stehe da echt auf dem Schlauch, dabei habe ich schon einiges gelesen.. 😞



  • Progressive schrieb:

    Ok, danke!
    Warum soll ich die <<,>> Operatoren denn außerhalb der Klasse definieren bzw. wo denn ?

    Du sollst das für << genauso machen wie >> (das schrieb ich doch)!

    Guck doch mal, was du geschrieben hast in der cpp-Datei:

    istream& operator>> (istream& in, APD& apd)
    ostream& APD::operator<<(ostream& out)
    

    Fällt dir da ein Unterschied auf? << ist in der Klasse, >> ist nicht in der Klasse. Im Header hast du einmal den >> als Friend markiert. Wenn du über print gehst, brauchst du << nicht einmal als friend markieren.

    Die Signatur von << sollte so sein:

    ostream& APD::operator<<(ostream& out, const APD& apd)
    

    Mit analog meinst du:

    ostream& operator<<(ostream& out, const APD&);	
    istream& operator>>(istream& in, const APD&);
    

    oder

    ostream& operator<<(ostream& out, APD& apd);	
    istream& operator>>(istream& in, APD& apd);
    

    Natürlich die Version mit const! Du willst doch nicht, dass eine Ausgabe das Objekt ändern kann.

    Ich verstehe den zweiten Parameter irgendwie nicht. Was bedeutet "APD&" und was "APD& apd" ?

    Das ist doch dieselbe Signatur. Einmal vergibst du einen Namen, einmal nicht.
    APD&: es wird ein Parameter vom Typ Referenz auf APD übergeben. Ein Name wird noch nicht vergeben.
    APD& apd: es wird ein Parameter vom Typ Referenz auf APD übergeben, welcher den Namen "apd" hat (wenn du keinen Namen vergibst, kannst du den Wert nicht benutzen - aber wenn du nur die Funktion deklarierst aber nicht definierst, brauchst du den Namen noch nicht).



  • Ich schrieb mist:

    ostream& APD::operator<<(ostream& out, const APD& apd)
    

    meinte natürlich:

    ostream& operator<<(ostream& out, const APD& apd)
    

    Ohne das APD::



  • wob schrieb:

    Das ist doch dieselbe Signatur. Einmal vergibst du einen Namen, einmal nicht.
    APD&: es wird ein Parameter vom Typ Referenz auf APD übergeben. Ein Name wird noch nicht vergeben.
    APD& apd: es wird ein Parameter vom Typ Referenz auf APD übergeben, welcher den Namen "apd" hat (wenn du keinen Namen vergibst, kannst du den Wert nicht benutzen - aber wenn du nur die Funktion deklarierst aber nicht definierst, brauchst du den Namen noch nicht).

    Erstmal vielen Dank für die Ausführlichkeit!
    Ich kann mir irgendwie nach wie vor nicht vorstellen, was da vor sich geht. Was bewirkt es, wenn ein Parameter vom Typ Referenz auf die Klasse (?) APD übergeht ? Wo wird das dann umgesetzt, wie verwendet,.. ? Was in der Klasse bekommt diesen Parameter ?



  • Also wenn ich

    ostream& operator<<(ostream& out, const APD&);
    

    außerhalb der Klasse definiere, ist das ok, innerhalb mag er nicht 😉

    Ich check's nicht.. woher weiß >> überhaupt, wo die Daten (also in dem Fall die Datei) herkommen ??



  • wob schrieb:

    Fällt dir da ein Unterschied auf? << ist in der Klasse, >> ist nicht in der Klasse. Im Header hast du einmal den >> als Friend markiert. Wenn du über print gehst, brauchst du << nicht einmal als friend markieren.

    Beide sind doch in der Klasse deklariert.



  • Ich versuchs nochmal zu antworten, empfehle dir aber ein Buch oder mal nach Operator Overloading rumzusuchen.

    Ich kann mir irgendwie nach wie vor nicht vorstellen, was da vor sich geht. Was bewirkt es, wenn ein Parameter vom Typ Referenz auf die Klasse (?) APD übergeht ? Wo wird das dann umgesetzt, wie verwendet,.. ? Was in der Klasse bekommt diesen Parameter ?

    Also nehmen wir mal eine einfache Funktion foo, die einen int als Parameter nimmt.

    Du kannst sie dem Compiler benanntmachen durch

    void foo(int);
    //oder: void foo(int hallo);
    //oder: void foo(int mirdochegal);
    

    Später, wenn du sie dann implementierst, benötigst du natürlich einen Namen:

    void foo(int i) { 
      // hier die implementierung, die auf i zugreifen will
      // wenn die Variable i hier nur noch aus Legacy-Gründen drin bleibt
      // und nicht mehr verwendet wird, könntest du den Namen auch hier weglassen
    }
    

    Solange du nur irgendwo die Funktion bekanntmachen willst, aber noch keine Implementierung hast, brauchst du noch keinen Namen für die Variable zu vergeben. Klar?

    Ich check's nicht.. woher weiß >> überhaupt, wo die Daten (also in dem Fall die Datei) herkommen ??

    Naja, wenn da irgendwo links >> rechts steht, übersetzt der Compiler dir das in den Funktionsaufruf operator>>(links, rechts) . Das funktioniert, wenn du einen passenden operator>> als freie Funktion definiert hast. Wenn du aber den Operator als Memberfunktion machst, dann kann der operator nur noch ein Argument nehmen (nämlich "rechts") und "links" ist fest auf das aktuelle Objekt eingestellt. Du könntest dann also nicht cout << apd schreiben, sondern müsstest apd << cout schreiben. Daher definiert man die Operatoren, die links des operators etwas anderes als *this haben können sollen, als freie Funktionen und nicht als Memberfunktionen.

    Beide sind doch in der Klasse deklariert.

    Nein, sind sie nicht.

    Mit friend davor sagst du nur: die folgende liebe Funktion, die nicht zu meiner Klasse gehört, darf trotzdem meine privaten Member benutzen. Damit wird die Funktion aber keine Memberfunktion.



  • wob schrieb:

    Ich versuchs nochmal zu antworten, empfehle dir aber ein Buch oder mal nach Operator Overloading rumzusuchen.

    Ja, hatte ebenein paar interessante Sachen gesehen, werd die mir morgen mal angucken.

    wob schrieb:

    Naja, wenn da irgendwo links >> rechts steht, übersetzt der Compiler dir das in den Funktionsaufruf operator>>(links, rechts) . Das funktioniert, wenn du einen passenden operator>> als freie Funktion definiert hast. Wenn du aber den Operator als Memberfunktion machst, dann kann der operator nur noch ein Argument nehmen (nämlich "rechts") und "links" ist fest auf das aktuelle Objekt eingestellt. Du könntest dann also nicht cout << apd schreiben, sondern müsstest apd << cout schreiben. Daher definiert man die Operatoren, die links des operators etwas anderes als *this haben können sollen, als freie Funktionen und nicht als Memberfunktionen.

    Vielen Dank, das war sehr nützlich! Das hat schonmal ein paar Irritationen ausgemerzt 🙂

    Beide sind doch in der Klasse deklariert.

    Nein, sind sie nicht.

    Mit friend davor sagst du nur: die folgende liebe Funktion, die nicht zu meiner Klasse gehört, darf trotzdem meine privaten Member benutzen. Damit wird die Funktion aber keine Memberfunktion.[/quote]
    friend wusste ich sogar bereits :p

    Bezüglich dem ~(istream in, APD& apd) ist

    Das in den bisherigen Beispielen Gesagte trifft auch dann zu, wenn es sich bei den Übergabeparametern statt um einfache Typen (wie int, float oder double) um Objekte handelt:

    class A {
    // ...
    };

    int count( A a);

    Hierbei wird ein Objekt vom Typ A per value an die Funktion count() übergeben. Weiter oben wurde gesagt, dass bei dieser Form der Übergabe eine Kopie des Parameters auf dem Stack angelegt wird.
    https://www.kompf.de/cplus/artikel/funcpar.html

    das, worum es geht ? Hatte nämlich vorhin auch gelesen, dass hierbei "..&" nicht der Adressoperator wäre bzw. man ihn damit nicht verwechseln dürfe 😕
    In meinem Kopf macht mir das "Objekt übergeben" irgendwie Schwierigkeiten. int, double, strings etc. übergeben, ja, klar.. aber wenn ich ein Objekt übergebe ? Wie oder wo genau wird geregelt, wie dieses verwertet wird ?
    Wie eine Funktion einen übergebenen Parameter behandelt, ist ersichtlich..



  • Hi,

    auf http://www.cpp-tutor.de/cpp/le12/ueberl_spez.html ist die Thematik glaube gut erklärt. Ich kriege auch mehr und mehr eine Vorstellung, was prinzipiell eigentlich so von sich geht. Glaube ich jedenfalls.

    Was mich die ganze Zeit irritiert hat, war die folgende "Schreibweise":

    z.B.:

    ostream& operator<<(ostream& out, const [b]APD& apd[/b])
    

    Ich konnte mit APD& apd nichts anfangen, auch wenn ich es an und für sich lesen kann. APD& ist eine Referenz auf die Klasse APD und diese erhält dann lediglich den Namen apd. Richtig ?
    Ich könnte also auch schreiben:

    ostream& operator<<(ostream& out, const APD& Name-des-Zeigers-der-auf-die-Klasse-APD-zeigt)

    ?

    Ich bin ja quasi gerade erst dabei, in C++ einzusteigen und das hatte mir ad hoc zuviel Ähnlichkeit mit "APD apd", was ja ein Objekt namens apd der Klasse APD erstellt.. 🙄



  • Ich konnte mit APD& apd nichts anfangen, auch wenn ich es an und für sich lesen kann. APD& ist eine Referenz auf die Klasse APD und diese erhält dann lediglich den Namen apd.

    APD& apd ist nicht eine Referenz auf die Klasse APD, sondern apd ist eine Referenz auf ein Objekt der Klasse APD. (Was soll "Referenz auf Klasse" sein?)

    Lies dir mal http://www.cplusplus.com/doc/tutorial/functions/ durch. Da ist ganz gut erklärt, wie Parameterübergabe an Funktionen funktioniert.



  • wob schrieb:

    APD& apd ist nicht eine Referenz auf die Klasse APD, sondern apd ist eine Referenz auf ein Objekt der Klasse APD. (Was soll "Referenz auf Klasse" sein?)

    Das stimmt wohl. Hab mir den kompletten Link durchgelesen. Inline ist nice to know, der Rest ist soweit bekannt..
    Das Objekt, auf das apd zeigt, ist das jenes, welches ich z.B. in main erstelle ?

    Normalerweise ist die Definition doch so: int& a bedeutet, der Referenzoperator & zeigt auf die Variable a, vom Typ int.

    Analog dachte ich also demnach: APD& ist eine Referenz, die auf die Variable apd vom Typ APD zeigt/vom Typ der Klasse APD.
    edit: Ahso, das wäre ja dann ein Objekt von APD ?! 💡



  • wob schrieb:

    Den opereator<< brauchst du, damit du in deinem Hauptprogramm sowas schreiben kannst:

    APD apd(input);
    // statt: apd.print();
    std::cout << apd << '\n';
    

    Dazu definiere den operator<< analog zu operator>>, also NICHT so wie du es gemacht hast, sondern definiere ihn analog AUSSERHALB der Klasse und gib ihm ostream& und const APD& als Parameter. Darin schreibst du dann mit << auf den ostream, den du am Ende returnst. Oder besser, rufe in dem operator<< einfach apd.print(os) auf, nachdem du dem print das ostream-Argument hinzugefügt hast.

    Da erhalte ich dann

    error: ‘std::ostream& APD::operator<<(std::ostream&, const APD&)’ must take exactly one argument
    ostream& APD::operator<<(ostream& out, const APD& apd);

    😕

    Entferne ich den zweiten Parameter, ergibt das

    error: no ‘std::ostream& APD::operator<<(std::ostream&)’ member function declared in class ‘APD’
    ostream& APD::operator<<(ostream& out);

    Dabei steht dort:

    ostream& APD::operator<<(ostream& out) 							
    	{     
    		out << m_SN;
    		return out;
    	}
    


  • Du musst die vorherigen Antworten auch mal lesen+verstehen! Oder kauf dir ein Buch!

    Mit APD::operator<< ist dieser bei dir ja wieder ein MEMBER von APD geworden, du sollst operator<< aber AUSSERHALB von APD definieren, also ohne APD:: davor.

    Ein letzter Versuch für ein Minimalbeispiel:

    #include <iostream>
    
    class APD {
      public:
        void print(std::ostream &os) const;
    
      private:
        int some_variable = 42;
    };
    
    void APD::print(std::ostream &os) const { 
        os << some_variable;
    }
    
    std::ostream &operator<<(std::ostream &os, const APD &apd) {
        apd.print(os);
        return os;
    }
    
    int main() {
        APD apd;
        std::cout << apd << '\n';
    }
    

Anmelden zum Antworten