C++ Überladen von Operatoren

Puepue

Komplett-PC-Aufrüster(in)
C++ Überladen von Operatoren

Hallo zusammen,
ich habe für die Schule Grundrechenoperatoren in C++ überladen (+,-,*,/)
Die Ein- und Ausgabeoperatoren << und >> müssen ja als externe Methode überladen werden - ich hab jetzt ein bisschen gegoogled aber nicht so recht verstanden, warum das so ist?
Kann mir das einer in Puepue-Deutsch erklären?
:huh:
 
AW: C++ Überladen von Operatoren

Das ist einfach:

cout << my_var;

Resultierender Aufruf: operator <<(cout, my_var);
Benötigte Signatur: operator <<(std::ostream&, const MyType&);

Als erstes Argument wird immer der Stream übergeben. Wenn man das jetzt als Methode innerhalb einer Klasse implementiert wird aber als erstes ein Zeiger auf das this-Objekt erwartet. Dies geschieht implizit, wird also vom Compiler automatisch erzeugt. Der linksseitige Operand ist also im Falle von << nicht vom Typ der Klasse!
 
AW: C++ Überladen von Operatoren

hmm kannst du mir vielleicht noch eine Sache erklären..

Ich hab jetzt für Multiplikation diesen Code:
Code:
TBruch TBruch::operator * (TBruch &b3)
{
	TBruch erg;

	erg.init(this->getZaehler() * b3.getZaehler(), this->getNenner() * b3.getNenner());

	return erg;
}
(die init-Methode ruft in dem Fall einfach nur eine Kürzung auf und setzs die Übergebenen Werte)

passend dazu in der TBruch.h
Code:
TBruch operator * (TBruch &b3);
(als public in der class)

und in der main.cpp ruf ich das einfach so auf:

Code:
TBruch b3(2,3);
TBruch erg ;
....
...
...
erg = b2 * b3;
erg.KonsolenAusgabe();

KonsolenAusgabe gibt mir einfach das Ergebnis als a/b in blau aus

Habe ich das richtig verstanden, dass das bei den << / >> Operatoren von der Syntax her anders ist?

Wie muss ich den Begriff "extern" überhaupt verstehen? nur außerhalb der Klasse (also eine einfach Funktion, wie man das so am Anfang gelernt hat?) oder ist hier Modularisierung auch wichtig?
 
AW: C++ Überladen von Operatoren

Ja, bei den << / >> Operatoren erfolgt der Aufruf in einer anderen Form.
Bei Operator * ist es zum Beispiel: operator *(a, b), da werden also Instanzen der Klasse übergeben.

"Extern" bedeutet hier einfach, dass die Funktion außerhalb der Klasse liegt, damit der erste Parameter ein Stream-Objekt ist und nicht das this-Objekt. Du kannst das dann entweder über getter/setter realisieren oder mittels friend-Funktionen.

Noch ein anderer Hinweis: Eventuell ist es sinnvoll, Operatoren wie operator + in der folgenden Form zu definieren: const MyType operator +(const MyType&, const MyType&) const. Das hat den einfachen Grund, dass Code wie dieser hier ungültigt wird: (a + b) = c;
Ohne das const im Rückgabetyp würde das nämlich kompilieren, allerdings gäbe diese Operation halt wenig Sinn ;)

Generell sollten die Operatoren so implementiert werden, wie es bei den Basisdatentypen der Fall ist (sollen sich also so wie bei int oder float verhalten).
 
AW: C++ Überladen von Operatoren

Auf die Gefahr hin, dass ich mich zum Affen mache..
Ich habe jetzt hier einen Code, der mir allerdings einige Fehlermeldungen auswirft


Hier die TBruch.h:
Code:
#pragma once

class TBruch
{
	private:
		int nenner;
		int zaehler;
		void setNenner(int n);
		void setZaehler(int z);
	public:
		//ctor
		TBruch(int zaehler=0, int nenner=1);
		//dtor
		~TBruch();
		void init (int zaehler, int nenner);
		TBruch addiere (TBruch &b3);
		TBruch multipliziere (TBruch &b3);
		TBruch subtrahiere (TBruch &b3);
		TBruch dividiere (TBruch &b3);
		int getNenner();
		int getZaehler();
		void KonsolenAusgabe ();
		int kuerze(int a, int b);
		
		static int counter;

		TBruch operator * (TBruch &b3);
		TBruch operator + (TBruch &b3);
		TBruch operator - (TBruch &b3);
		TBruch operator / (TBruch &b3);
};

//ermoeglicht cout << b3; => Ausserhalb der Klasse!
ostream & operator << (ostream &o, TBruch &b3);

Die letzte Zeile ist die, die Probleme macht, o und b3 seien nicht-deklarierte Bezeichner

In der Truch.cpp sieht die Methode so aus:
Code:
//ueberladen, des Ausgabeoperators => Wichtig: Global!!
ostream & operator << (ostream & o, TBruch & b)
{
	o << b.getZaehler() << "/" << b.getNenner();
	return o; //dann geht cout << b;
}

Habe dort diese Includes und den namespace std:
#include <iostream>
#include "TBruch.h"
#include <windows.h>

using namespace std;



in der main.cppp würde ich dann (wenn es denn funktionieren würde) einfach
cout << b3;
machen und hätte dann gerne bspw. 1/3 als Konsolenausgabe..

ABER irgendwas scheine ich ja in der .h falsch zu machen?
 
AW: C++ Überladen von Operatoren

Hast du es mal mit
Code:
std::ostream& operator <<(std::ostream &out, TBruch &b)
versucht? Du kannst die Funktion auch als "friend" deklarieren und dann direkt auf die Variablen zugreifen (ohne Umweg über getter-Funktionen).

Von einem "using namespace xyz" in einer Header-Datei rate ich übrigens dringend ab, da dies für alle Dateien übernommen wird, die diesen Header dann einbinden. Kann zu mehr oder weniger lustigen Fehlern führen :ugly:

Noch ein Tipp: Nutze "const".
Code:
const TBruch operator *(const TBruch &tb) const;
Das erste const sorgt für einen konstanten Rückgabetyp (verhindert so Sachen wie a * b = 3), das zweite verhindert eine (unabsichtliche) Änderung des übergebenen Parameters und das dritte const sorgt dafür, dass diese Methode auch auf const-Objekte aufrufbar ist:
Code:
const TBruch b1;
Hier können nur Methoden aufgerufen werden, die als const markiert sind, also garantieren, dass es wirklich konstant bleibt.

Wenn man einen Basisdatentyp zurückgibt, muss man übrigens nicht const davor schreiben, da der Compiler keine Wertzuweisung zulässt.
 
Zuletzt bearbeitet:
AW: C++ Überladen von Operatoren

Bei der Variante
std::ostream& operator <<(std::ostream, TBruch &b3) bzw.
std::ostream& operator <<(std::ostream, TBruch &b)
öffnet VS eine excpt.h und gibt diese Fehlermeldung aus:

Fehler 1 error C2144: Syntaxfehler: 'int' sollte auf ';' folgen c:\programme\microsoft visual studio 9.0\vc\include\excpt.h 33


das using namespace habe ich nur in der .cpp Datei drinne in der .h ist lediglich ein #pragma once drinne..


PS:
Zu dem Fehler steht im inet bei msdn:

Syntaxfehler: 'Typ' sollte auf 'Token' folgen
syntax error : 'type' should be preceded by 'token'
Der Compiler hat ein token erwartet, jedoch einen type gefunden.
Dieser Fehler kann durch das Fehlen einer schließenden geschweiften Klammer, einer rechten Klammer oder eines Semikolons verursacht werden.
C2144 kann auch auftreten, wenn ein Makro mit einem CLR-Schlüsselwort erstellt wird, das ein Leerzeichen enthält.
Möglicherweise wird C2144 auch angezeigt, wenn Sie eine Typweiterleitung durchführen. Weitere Informationen finden Sie unter Type Forwarding.


Wenn ich ein Semikolon hinter die besagte Zeile schreibe kommt heraus:
Fehler 1 error C2248: "std::basic_ios<_Elem,_Traits>::basic_ios": Kein Zugriff auf private Member, dessen Deklaration in der std::basic_ios<_Elem,_Traits>-Klasse erfolgte. c:\programme\microsoft visual studio 9.0\vc\include\ostream 584
 
Zuletzt bearbeitet:
AW: C++ Überladen von Operatoren

Upps... habe da auch ein "&out" geschludert, habe das oben im Code korrigiert (std::ostream&).

Hier nochmal im Ganzen:
Code:
class Punkt
{
public:
    Punkt(int x, int y);
    ~Punkt();
    ...

private:
    int m_x, m_y;
    friend std::ostream& operator <<(std::ostream &out, const Punkt &p);
};

// irgendwo anders
std::ostream& operator <<(std::ostream &out, const Punkt &p)
{
    out << "(" << p.m_x << ", " << p.m_y << ")";
    return out;
}
Das funktioniert bei mir so. Man kann jetzt noch überlegen, ob man friend weglässt und die Funktionalität durch Getter nachbildet. Das hieße hier konkret, die Zeile mit "friend std::ostream& ..." rausschmeißen, Getter für m_x und m_y (a la getX(), getY()) hinzufügen und dann diese Funktionen im überladenen Operator aufrufen. Ist eigentlich das bessere Design, war nur zu faul das alles zu schreiben ;)
 
Zurück