Überaldung von "="



  • @SeppJ: Warum muss man hier const verwenden und was bewirkt const hier?

    Schon mal Danke für die vielen hilfreichen Antworten!


  • Mod

    vip@r schrieb:

    @SeppJ: Warum muss man hier const verwenden und was bewirkt const hier?

    Weil du sonst der Funktion keine temporären (oder allgemein konstante) Werte per Referenz übergeben kannst. Hier hast du einen solchen Wert vorliegen, denn bei

    a = 5;
    

    steht links ein INT, rechts ein int. Einen operator=(INT, int) hast du aber nirgends definiert. Aber es gibt ja noch den Konstruktor INT(double v) , so dass der int über die Konvertierung nach double in einen INT konvertiert werden kann. Das dabei entstehende Objekt ist aber ein temporay vom Typ INT und kann nicht verändert werden. Die ursprüngliche Funktionssignatur INT& operator = (INT &v) sagt aber gerade aus, dass auch das v sich verändert (bzw. verändern kann), das passt daher nicht zusammen.



  • Danke SeppJ für die ausführliche Antwort!

    Ich hab jetzt mal versucht für einen eigenen Datentypen Vektor den output-Stream zu überladen. Leider funktioniert das noch nicht so ganz. Der Compiler spuckt mir einige Fehler aus. Hier der Code:

    Deklaration in der Klasse:

    friend ostream &operator << (ostream &output, const Vector &v);
    

    Implementierung:

    ostream& Vector::operator << (ostream &output, const Vector &v)
    {
    	output << "(" << v.x << "," << v.y << ")" << std::endl;
    
    	return output;
    }
    

    Fehlermeldungen:

    Fehler	1	error C2143: Syntaxfehler: Es fehlt ';' vor '&'	
    
    Fehler	2	error C2433: 'ostream': 'friend' bei der Deklaration von Daten nicht zulässig	
    
    Fehler	3	error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.	
    
    Fehler	4	error C2061: Syntaxfehler: Bezeichner 'ostream'	
    
    Fehler	5	error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.	
    
    Fehler	6	error C2805: Binärer Operator '<<' hat zu wenig Parameter	
    
    Fehler	7	error C2143: Syntaxfehler: Es fehlt ';' vor '&'	
    
    Fehler	8	error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.	
    
    Fehler	9	error C2086: 'int ostream': Neudefinition	
    
    Fehler	10	error C2065: 'output': nichtdeklarierter Bezeichner	
    
    Fehler	11	error C2059: Syntaxfehler: 'const'	
    
    Fehler	12	error C2143: Syntaxfehler: Es fehlt ';' vor '{'	
    
    Fehler	13	error C2447: '{': Funktionsheader fehlt - Parameterliste im alten Stil?	
    
    Fehler	14	error C2143: Syntaxfehler: Es fehlt ';' vor '&'	
    
    Fehler	15	error C2433: 'ostream': 'friend' bei der Deklaration von Daten nicht zulässig	
    
    Fehler	16	error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.	
    
    Fehler	17	error C2061: Syntaxfehler: Bezeichner 'ostream'	
    
    Fehler	18	error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.	
    
    Fehler	19	error C2805: Binärer Operator '<<' hat zu wenig Parameter
    

  • Mod

    Bitte mal dritten Link in meiner Signatur lesen. Spekulation wäre alles von vergessenem Semikolon zu vergessener Auflösung des Namespaces std. Das bringt nichts, wild herum zu raten.



  • friend ostream &operator << (ostream &output, const Vector &v); 	
    
    ostream& operator << (ostream &output, const Vector &v)
    {
    return output << "(" << v.x << "," << v.y << ")" << std::endl;
    }
    

    Das ist keine Memberfunktion der Klasse. So dachte dein Compiler an den shift operator.



  • Also:

    Benutzte IDE: Visual Studio 2010
    Benutzter Compiler: Der, der in VS2010 eingebaut ist.

    Ich hab in verteilten Dateien gearbeitet. Ich kopiere jetzt alles für mich relevant erschienene hier rein:

    Header-Datei:

    #ifndef TEST_H
    #define TEST_H
    
    class Vector
    {
    private:
    	double x;
    	double y;
    	double skalar;
    
    public:
    	Vector();
    	Vector(double _x, double _y);
    
    	Vector &operator + (const Vector vec);
    	Vector &operator - (const Vector vec);
    	double &operator * (const Vector vec);
    	friend ostream &operator << (ostream &output, const Vector &v);
    };
    
    #endif TEST_H
    

    Implementierungsdatei:

    #include<iostream>
    #include"test.h"
    //using namespace std;
    
    Vector::Vector() : x(0), y(0)
    {
    
    }
    
    Vector::Vector(double _x, double _y) : x(_x), y(_y)
    {
    
    }
    
    Vector& Vector::operator + (const Vector vec)
    {
    	x = x + vec.x;
    	y = y + vec.y;
    
    	return *this;
    }
    
    Vector& Vector::operator - (const Vector vec)
    {
    	x = x - vec.x;
    	y = y - vec.y;
    
    	return *this;
    }
    
    double& Vector::operator * (const Vector vec)
    {
    	x = x * vec.y;
    	y = y * vec.y;
    	skalar = x + y;
    
    	return skalar;
    }
    
    ostream& Vector::operator << (ostream &output, const Vector &v)
    {
    	output << "(" << v.x << "," << v.y << ")" << std::endl;
    
    	return output;
    }
    

    Die main-Datei hat keine Auswirkung auf die Fehler! Egal ob ich Vektoren deklariere oder nicht, ob ich sie schon ausgeben lasse, oder nicht. Alles egal. Deshalb lass ich die main mal weg. Ich hoff, jetzt entspricht es dem Standard hier im Board.


  • Mod

    std::ostream

    Dazu brauchst du noch entweder den Header iosfwd , ostream oder gleich iostream .



  • Den header <iostream> hab ich aber in der Implementierungsdate schon eingebunden, oder meinst du mit deiner letzten Antwort, dass ich den in der Klassendatei auch noch einbinden soll?

    klasse:

    friend std::ostream &operator << (std::ostream &output, const Vector &v);
    

    Implementierung:

    std::ostream& Vector::operator << (std::ostream &output, const Vector &v)
    {
    	output << "(" << v.x << "," << v.y << ")" << std::endl;
    
    	return output;
    }
    

    So siehts nach den veränderungenaus. alles andere ist so geblieben. Fehlermeldung:Fehler 1 error C2039: '<<': Ist kein Element von 'Vector'



  • vip@r schrieb:

    Header-Datei:

    #ifndef TEST_H
    #define TEST_H
    
    class Vector
    {
    private:
    	double x;
    	double y;
    	double skalar;
    public:
    	Vector();
    	Vector(double _x, double _y);
    
    	Vector &operator + (const Vector vec);
    	Vector &operator - (const Vector vec);
    	double &operator * (const Vector vec);
    	friend ostream &operator << (ostream &output, const Vector &v);
    };
    

    🙄
    Du hast wieder ? mit ?= verwelchselt, diesmal im Falle +, - und * anstelle des Fragezeichens.

    int a = 23;
    int b = 42;
    a+b; //verändert a nicht!!!
    

    Im Wesentlichen hast du den letzten Absatz meines vorherigen Beitrags komplett ignoriert.



  • Ich wollte mit dieser *neuen* Klasse die Überladung der Operatoren nicht implementieren. Ich hab deinen letzten Absatz deiner Antwort sehr wohl gelesen und deine Tips im Projekt berücksichtigt.



  • Bei der Implementation von ostream& operator <<() mußt Du Vector:: weglassen, da sie kein Member von Vector ist. (Hat Nymer schon mal erwähnt)



  • @Krümelkacker: Hier mal nochmal die Variante die du mir vorgeschlagen hast. Ich hoffe, dass das dem entspricht, was du mir beibringen wolltest:

    #ifndef TEST_H
    #define TEST_H
    
    class Vector
    {
    private:
    	double x;
    	double y;
    	double skalar;
    
    public:
    	Vector();
    	Vector(double _x, double _y);
    
    	Vector &operator += (const Vector vec);
    	Vector &operator + (const Vector vec);
    
    	Vector &operator -= (const Vector vec);
    	Vector &operator - (const Vector vec);
    
    	double &operator * (const Vector vec);
    	friend std::ostream &operator << (std::ostream &output, const Vector &v);
    };
    
    #endif TEST_H
    
    #include<iostream>
    #include"test.h"
    
    Vector::Vector() : x(0), y(0)
    {
    
    }
    
    Vector::Vector(double _x, double _y) : x(_x), y(_y)
    {
    
    }
    
    Vector& Vector::operator += (const Vector vec)
    {
    	x = x + vec.x;
    	y = y + vec.y;
    
    	return *this;
    }
    
    Vector& Vector::operator + (const Vector vec)
    {
    	Vector tmp(x, y);
    
    	return tmp += vec;
    }
    
    Vector& Vector::operator -= (const Vector vec)
    {
    	x = x - vec.x;
    	y = y - vec.y;
    
    	return *this;
    }
    
    Vector& Vector::operator - (const Vector vec)
    {
    	Vector tmp(x, y);
    
    	return tmp -= vec;
    }
    
    double& Vector::operator * (const Vector vec)
    {
    	x = x * vec.y;
    	y = y * vec.y;
    	skalar = x + y;
    
    	return skalar;
    }
    
    std::ostream& operator << (std::ostream &output, const Vector &v)
    {
    	output << "(" << v.x << "," << v.y << ")" << std::endl;
    
    	return output;
    }
    

    Danke Nymer, dass du mich nochmal drauf aufmerksam gemacht hast! Jetzt funktioniert übrigens die gesamte Klasse! Danke an euch. Das hat mir sehr weiter geholfen! Über eine Rückmeldung von Krümelkacker würde ich mich sehr freun, ob das dem entspricht, was er mir beibringen wollte 🙂



  • Du kannst übrigens direkt:

    return output << "(" << v.x << "," << v.y << ")" << std::endl;
    

    schreiben anstatt:

    output << "(" << v.x << "," << v.y << ")" << std::endl;
    
        return output;
    

    , was den gleichen Effekt hat.
    Ich persönlich finde das schöner 😉 .



  • vip@r schrieb:

    @Krümelkacker: Hier mal nochmal die Variante die du mir vorgeschlagen hast. Ich hoffe, dass das dem entspricht, was du mir beibringen wolltest:

    Du gibst bei operator+ und co Referenzen auf temporäre Objekte zurück, die dann ungültig werden. Bei operator+ und co fehlt noch ein const am Ende der Deklarationen. Die Parameter würde ich als Referenz-auf-konstant entgegen nehmen. Operator verändert das Objekt auf der linken Seite und gibt eine Referenz auf ein Datenelement der linken Seite zurück*. Das ist eine extrem schlechte Idee für einen binären Operator, der normalerweise seine Operanden nicht verändert und nur einen neuen Wert zurück gibt.

    Nur mal so ein Beispiel:

    Vector& Vector::operator + (const Vector vec)
    {
    	Vector tmp(x, y);
    	return tmp += vec;
    }
    

    hätte lieber

    Vector Vector::operator + (const Vector& vec) const // <- const nicht vergessen!
    { //  ^ keine Referenz!!               ^ Referenz!!
        Vector tmp(x, y);
        tmp += vec;
        return tmp; // <-- so aufgeschrieben erlaubt es noch die NRVO-Optimierung
    }
    

    heißen sollen. Allerdings kannst du es auch so schreiben:

    Vector Vector::operator + (const Vector& vec) const
    {
        return Vector(x+vec.x,y+vec.y);
    }
    

    wobei ich natürlich nicht weiß, was das mit deinem skalar -Member da soll. Der wird ja nicht mal irgendwo initialisiert!

    Prinzipiell würde ich operator+, operator-, operator* aus "Symmetriegründen" auch als freie Funktionen definieren. Was das genau heißt, hatte ich letztens schon angedeutet.

    Du musst übrigens nicht das Rad neu erfinden. Es gibt beispielsweise eine nette Matrix/Vektor-Bibliothek mit diversen netten Funktionen: Eigen.



  • krümelkacker schrieb:

    Prinzipiell würde ich operator+, operator-, operator* aus "Symmetriegründen" auch als freie Funktionen definieren. Was das genau heißt, hatte ich letztens schon angedeutet.

    Das würde ich unbedingt machen und so macht man es afaik auch.
    Wenn du z.B. noch multiplizieren mit einem Skalar hinzufügst, geht das so nicht (V*s) geht (s*V) nicht.

    Du musst übrigens nicht das Rad neu erfinden. Es gibt beispielsweise eine nette Matrix/Vektor-Bibliothek mit diversen netten Funktionen: Eigen.

    Eigen ist toll. Einfach inkludieren und fertig.
    Vielleicht will er aber auch einfach operatoren Überladung üben.



  • Danke Leute, für eure tollen Beispiele und Hilfe!

    Ja, ich will in der Tat die Operatorüberladung üben. Ich werde mir so gut es geht mir eure Tips zu herzen nehmen! Ich hab hier nun übrigens wieder ein Problemchen mit einer Klasse und einer Überladung. Verwendete IDE und Compiler: VS2010.

    Header:

    class Bitvector
    {
    private:
    	unsigned int bits;	//Anzahl der Bits im Bitvektor
    	unsigned char byte;	//chars aus denen sich der Bitvektor zusammensetzt
    	unsigned char* bv;	//pointer auf die aneinandergereihten chars
    
    public:
    	Bitvector();
    	Bitvector(unsigned int bits);
    	~Bitvector();
    
    	friend std::ostream& operator << (std::ostream& output, Bitvector &bv);
    };
    

    Implementierung:

    std::ostream& operator << (std::ostream &output, const Bitvector &bv)
    {
    	bv.bits; //hier gibts den Fehler!
    
    return output;
    }
    

    Compilerfehler:

    Fehler	1	error C2248: "Bitvector::bits": Kein Zugriff auf private Member, dessen Deklaration in der Bitvector-Klasse erfolgte.
    

    Ich brauch in der Überladung Zugriff auf die "bits" der Klasse. Wie mach ich das dann hier? Ich hab eigentlich gedacht, dass ich hier ohne Probleme mein Wissen von gester anwenden kann, aber schon kommt wieder was das mich raushaut... Könnt ihr mir helfen?

    Edit:
    Wenn ich den Zugriffsspezifizierer private auf public ändere, bekomme ich hier Zugriff auf bits. Warum kann ich bei dieser Ausgabeoperator-Überladung nicht, wie in "normalen" Methoden üblich, auf private-Variablen zugreifen? Wie gehe ich dann hier vor? Muss ich eine Methode schreiben, die mir den Wert private-Var. liefert? Oder gibt es eine andere Möglichkeit?



  • friend gewährt einer Methode Zugriff auf private Daten einer Klasse (solltest du wissen). Deine beiden Methoden haben nicht die gleiche Signatur, weshalb die Implementation nicht als die friend Methode erkannt wird. ( const zuwenig)

    Übrigens wie mein Compiler richtig meckert, musst du so unbedingt den Copy-Konstruktor und den operator= überladen. Am besten gar keine Pointer verwernden.



  • Wenn ich deine Antwort richtig verstehe, muss ich also in der Implementierung das friend-Schlüsselwort auch noch schreiben, oder? Leider finde ich hierzu in meinem Buch/Unterlagen leider kein Beispiel wo das gezeigt wird an welche Stelle das friend platziert werden muss...

    Edit: "friend" darf außerhalb einer Klasse nicht verwendet werden, sagt mein Compiler. Wo ist dann der Fehler?

    Das friend den Zugriff auf private Vars/Methoden regelt weiß ich natürlich, deswegen hab ich es ja in der h-Datei auch hingeschrieben 🙂



  • [cpp]class Bitvector
    {
    ...
    friend std::ostream& operator << (std::ostream& output, Bitvector &bv);
    }; [/cpp]

    std::ostream& operator << (std::ostream &output, const Bitvector &bv)
    {
        bv.bits; //hier gibts den Fehler!
    
    return output;
    }
    

    Das meinte ich. (Steht da doch auch(Hmm.. vielleicht auch etwas mehrdeutig))



  • Ich bin blind. Leider. Aber dennoch Danke 🙂

    Nun hab ich die Überladung um das hier erweitert:

    std::ostream& operator << (std::ostream &output, const Bitvector &bv)
    {
    	for(unsigned int i=0; i<=bv.bits; i++)
    	{
    		if(i == 0)
    		{
    			output << bv.getBit(i);  //Fehler
    		}
    		else if((i%4) == 0)
    		{
    			output << " " << bv.getBit(i);  //Fehler
    		}
    		else if(i > 0)
    		{
    			output << bv.getBit(i);  //Fehler
    		}
    	}
    
    return output;
    }
    

    Probleme macht nun die getBit()-Methode. Der Compiler sagt: "Fehler 1 error C2662: 'Bitvector::getBit': this-Zeiger kann nicht von 'const Bitvector' in 'Bitvector &' konvertiert werden"

    Die getBit()-Methode gibt einen einzelnen char zurück. Wie greife ich korrekt auf Methoden aus Überladungen zu? Es liegt am const, nicht wahr? Muss ich nun die getBit() als const deklarieren?


Anmelden zum Antworten