Überladen von Operatoren
-
Hallo,
ich habe von oben genanntem Thema anscheined noch etwas nicht verstanden.....
Wenn ich einen Operator in meiner Header datei überladen möchte,
funktioniert das so wunderbar:Vector operator = (const Vector &v) {x = v.x; y = v.y; z = v.z; return *this;}warum meckert er wenn ich ihm mehr als zwei Parameter geben möchte, wie z.B.
Vector operator + (const Vector &a, const Vector &b) {a.x + b.x, a.y + b.y, a.z + b.z; return *this;}
-
Weil operator+ als Memberfunktion mit zwei Argumenten nicht existiert. Es braucht diese 2 Argumente auch nicht.
Wenn du x,y, z als Objekte der Klasse Vector hast.
Dann wird
z = x + y;
ausgewertet zu
z = x.operator+(y);
Das heisst die Funktion wird auf dem ersten Objekt aufgerufen.
-
Bei jedem Operator ist festgelegt, wie viele Operanden er benötigt. operator+ ist ein binärer Operator, d.h. er braucht zwei Operanden. Wenn du ihn allerdings innerhalb einer Klasse definierst, ist this bereits ein Operand, d.h. du hast drei Operanden. Du kannst nun einen Parameter wegwerfen oder, was besser ist, den Operator als freie Funktion definieren. Einen guten Artikel zum Überladen von Operatoren gibts im Magazin: http://www.c-plusplus.net/forum/232010
-
Lybrial schrieb:
warum meckert er wenn ich ihm mehr als zwei Parameter geben möchte, wie z.B.
Weil innerhalb der Klasse deklariert es in wirklichkeit 3 Parameter sind, this wird ja auch (unsichtbar) übergeben.
Raus aus der Klasse und drunterschreiben.class Vector{ ... }; Vector operator + (const Vector &a, const Vector &b) {Vector c; c.x=a.x+b.x; c.y=a.y+b.y; c.z=a.z+b.z; return c;}
-
Innerhalb von der Klasse würde es von der Syntax her dann so aussehen?
Vector operator + (const Vector &a) { x + operator + (a.x); y + operator + (a.y); z + operator + (a.z); return *this; }ich frage extra weil
Vector operator + (const Vector &a) { x = x.operator + (a.x); ..... }funktioniert net^^
-
Nein, du solltest keinen der Operanden bei operator+ verändern. Wär ja auch komisch, wenn man bei c = b + a auf einmal b verändert.
-
Vector operator + (const Vector &a) { x + a.x; y + a.y; z + a.z; return *this; }
-
Lybrial schrieb:
Vector operator + (const Vector &a) { x + a.x; y + a.y; z + a.z; return *this; }Ganz großer Blödsinn. Der Operator tut nichts und gibt nur eine Kopie von *this zurück - ohne dass sich irgendwas ändert.
-
Ich schwöre, gestern hat es nicht funktioniert -.-
Jetzt schon....
Vector Vector::operator + (const Vector &v) { x = x + v.x; ......aber schon gehts weiter:
wenn ich jetzt biespielsweise eine Operator überladung vorgenommen habe wie diese:
Vector Vector::operator / (const float f) { x = x / f; y = y / f; z = z / f; return *this; }Wieso kann das Programm dann das hier nicht?
// to normalize a vector (lenth 1) Vector Vector::VectorNormalize(const Vector &v) { return v / sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); }da steht ja dann nix anderes als Vector / float
da hab ich ihm ja schon gesagt was er damit machen soll
nämlichx/f
y/f
z/f
-
dein Operator / verändert in der Rechnung Vector a = v / 9.f; v und das darf nicht sein.
greetz KN4CK3R
-
Aber wenn ich ne lokale kopie erzeuge, dann ist die hinterher nicht mehr gültig....
Wenn ich nen Vektor in die Methode stecke, und ihn normalisieren möchte, dann will ich doch das v verändert wird...
-
Lybrial schrieb:
Aber wenn ich ne lokale kopie erzeuge, dann ist die hinterher nicht mehr gültig....
Natürlich ist sie gültig, wenn du sie zurückgibst. Schau dir nochmal den von mir geposteten Link an, wie man die Operatoren standardmäßig implementiert.
Wenn ich nen Vektor in die Methode stecke, und ihn normalisieren möchte, dann will ich doch das v verändert wird...
Beim Normalisieren kann man drüber streiten, aber bei c = a + b erwartet keiner, dass a verändert wird (ich wiederhole mich).
-
Michael E. schrieb:
Lybrial schrieb:
Aber wenn ich ne lokale kopie erzeuge, dann ist die hinterher nicht mehr gültig....
Natürlich ist sie gültig, wenn du sie zurückgibst. Schau dir nochmal den von mir geposteten Link an, wie man die Operatoren standardmäßig implementiert.
Wenn ich nen Vektor in die Methode stecke, und ihn normalisieren möchte, dann will ich doch das v verändert wird...
Beim Normalisieren kann man drüber streiten, aber bei c = a + b erwartet keiner, dass a verändert wird (ich wiederhole mich).
3.2 operator+, -, *, /, %
Semantik: Addition, Subtraktion, Multiplikation, Division, Modulo. Es wird ein neues Objekt mit dem Ergebniszustand erzeugt. Die folgenden Ausführungen gelten jeweils analog für -, *, / und %.
Übliche Deklaration:C/C++ Code:
const X operator+(X const& lhs, X const& rhs);
C/C++ Code:
const X operator+(X const& lhs, X const& rhs);Übliche Implementierung:
C/C++ Code:
const X operator+(X const& lhs, X const& rhs)
{
/* Erzeugen eines neuen Objektes, dessen Attribute gezielt einzeln gesetzt werden. Oder: */
X tmp(lhs); //Kopie des linken Operanden
tmp += rhs; //Implementierung mittels des +=-Operators
return tmp;
}
C/C++ Code:
const X operator+(X const& lhs, X const& rhs)
{
/* Erzeugen eines neuen Objektes, dessen Attribute gezielt einzeln gesetzt werden. Oder: */
X tmp(lhs); //Kopie des linken Operanden
tmp += rhs; //Implementierung mittels des +=-Operators
return tmp;
}In vielen Fällen macht das Vorhandensein des operator+ auch die Existenz des operator+= sinnvoll, um die kürzere Schreibweise a += b an Stelle von a = a + b zu ermöglichen. Um das Verhalten beider Operatoren konsistent zu halten ist es daher üblich, operator+ im Sinne von operator+= zu implementieren wie gezeigt. Um eine implizite Typumwandlung des ersten Operanden zu ermöglichen werden die binären arithmetischen Operatoren üblicherweise als freie Funktionen definiert.
Wird der Operator nicht mittels operator+= implementiert, benötigt er meist Zugriff auf private Attribute von X. In dem Fall wird er häufig als friend der Klasse deklariert oder greift auf eine öffentliche Methode der Klasse zu, die die eigentliche Operation ausführt:C/C++ Code:
const X X::plus(X const& rhs) const; //Implementiert die Addition
const X operator+(X const& lhs, X const& rhs)
{
return lhs.plus(rhs);
}
C/C++ Code:
const X X::plus(X const& rhs) const; //Implementiert die Addition
const X operator+(X const& lhs, X const& rhs)
{
return lhs.plus(rhs);
}Das ist die betreffende Stelle, allerdings werden hier für operator + zwei Parameter reingesteckt, was garnicht möglich ist wenn man sie (wie es sauberes programmieren ist) außerhalb der Klasse definiert.
-
Lybrial schrieb:
Das ist die betreffende Stelle, allerdings werden hier für operator + zwei Parameter reingesteckt, was garnicht möglich ist wenn man sie (wie es sauberes programmieren ist) außerhalb der Klasse definiert.
Doch, als freie Funktion benötigt operator+ genau zwei Parameter.
-
Error: "must take either zero or one argument"
Tritt im Header auf, dort ist die Überladung deklariert
und im entsprechenden cpp File definiert!
-
Lybrial schrieb:
Error: "must take either zero or one argument"
Tritt im Header auf, dort ist die Überladung deklariert
und im entsprechenden cpp File definiert!Glaub ich dir nicht. Hast du den Operator innerhalb einer Klasse deklariert?
-
Ja!
class lCVector3 { public: struct { float x; float y; float z; }; // coords lCVector3(); // standart lCVector3(const lCVector3 &v); // copy lCVector3(const float f); // normal each element, same number lCVector3(const float _x, const float _y, const float _z); // normal each element, different number lCVector3(const float *pfComponent); // normal array with three elements // operation assignments lCVector3 operator = (const lCVector3 &v); lCVector3 operator += (const lCVector3 &v); lCVector3 operator -= (const lCVector3 &v); lCVector3 operator *= (const lCVector3 &v); lCVector3 operator *= (const float f); lCVector3 operator /= (const lCVector3 &v); lCVector3 operator /= (const float f); // arithmetical operations lCVector3 operator + (const lCVector3 &v); lCVector3 operator - (const lCVector3 &v); lCVector3 operator * (const lCVector3 &v); lCVector3 operator * (const float f); lCVector3 operator / (const lCVector3 &v); lCVector3 operator / (const float f); // compare operations bool operator == (const lCVector3 &v); bool operator != (const lCVector3 &v); // function declaration float lCVector3Length(const lCVector3 &v); float lCVector3LengthSq(const lCVector3 &v); lCVector3 lCVector3Normalize(const lCVector3 &v); lCVector3 lCVector3NormalizeEx(const lCVector3 &v); lCVector3 lCVector3Cross(const lCVector3 &v1, const lCVector3 &v2); float lCVector3Point(const lCVector3 &v1, const lCVector3 &v2); float lCVector3Angle(const lCVector3 &v1, const lCVector3 &v2); lCVector3 lCVector3InterpolateCoords(const lCVector3 &v1, const lCVector3 &v2, const float p); lCVector3 lCVector3InterpolateNormal(const lCVector3 &v1, const lCVector3 &v2, const float p); };
-
Dann zitier ich dich mal selbst:
wenn man sie (wie es sauberes programmieren ist) außerhalb der Klasse definiert.
Ansonsten haben dir auch schon genug Leute gesagt, dass der Operator als freie Funktion definiert werden soll und eben nicht in einer Klasse.
-
Man deklariert innerhalb der Klasse
und definiert außerhalb.Ist doch normal.....
Und genau so hab ichs gemacht,
sehe dir den letzten Post von mir an, da hab ich
mal den header gepostet, alles nur deklarationen
nix definiert.
-
Lybrial schrieb:
Man deklariert innerhalb der Klasse
und definiert außerhalb.Nein, eine Funktion ist entweder innerhalb einer Klasse deklariert und definiert oder außerhalb. Beides gibts nicht. Du hast die Definition der Funktion einfach nur räumlich getrennt von der Klassendefinition, aber die Signatur der Funktionsdefinition sagt ganz klar, dass die Funktion zur Klasse gehört.
class Foo { void bar(); } void Foo::bar() // bar gehört zu Foo { } void baz() // freie Funktion { }
-
Versteh ich jetzt nicht ganz, funktioniert es dann grundsätzlich nicht
wenn man das so macht oder ist das nur "unschön"Ein Beispiel das ich gemacht habe, eine Log-Klasse:
Header
#ifndef __LOGHANDLER #define __LOGHANDLER #include <stdio.h> #include "Singleton.hpp" enum LOGLEVEL { L_OK, L_ERROR, L_FATAL_ERROR, L_INFO L_WARN L_DEBUG }; class CLogHandler : public TSingleton<CLogHandler> { public: CLogHandler(); //constructor ~CLogHandler(); //destructor void createLogHandler(const char *LogName); //new logfile void message(const char *File, int Line, const char *Time, const char *msg, LOGLEVEL level); //writes message into logfile private: FILE *m_Logfile; //the FILE ;) const char* convertEnum(LOGLEVEL level); //to convert the enums ;) }; #endifdie cpp dazu, in der die Methoden definiert sind:
#include <iostream> #include <string.h> #include "LogHandler.hpp" using namespace std; //constructor CLogHandler::CLogHandler(){}; //destructor CLogHandler::~CLogHandler(){ message(__FILE__, __LINE__, __TIME__,"End of logfile!", L_INFO); fclose(m_Logfile); } //create logfile and write head void CLogHandler::createLogHandler(const char *LogName) { try { m_Logfile = fopen(LogName, "w");//fopen = fileopen, w = write if (m_Logfile == NULL) { throw "Datei konnte nicht geoeffnet werden!"; } } catch (char *ErrorString) { cout << "Fehler aufgetreten: " << ErrorString << endl; cout << "Programm wird beendet!" << endl; exit(0); } message(__FILE__, __LINE__, __TIME__, "THIS IS THE LOGFILE!!!", L_INFO); //print out actual build-configuration #ifdef _DEBUG message(__FILE__, __LINE__, __TIME__, "BUILD: DEBUG", L_INFO); #else message(__FILE__, __LINE__, __TIME__, "BUILD: RELEASE", L_INFO); #endif //close logfile and open it again with append fclose(m_Logfile); try { m_Logfile = fopen(LogName, "a");//fopen = fileopen, a = append if (m_Logfile == NULL) { throw "Datei konnte nicht geoeffnet werden!"; } } catch (char *ErrorString) { cout << "Fehler aufgetreten: " << ErrorString << endl; cout << "Programm wird beendet!" << endl; exit(0); } } //message method to print a message into the logfile with LOGLEVEL void CLogHandler::message(const char *File, int Line, const char *Time, const char *msg, LOGLEVEL level) { fprintf(m_Logfile,"[<%s> - <%s>] at: <%20s>: <%d> <%s>\n", convertEnum(level), Time, File, Line, msg); fflush(m_Logfile);//forces instantly writing into the file } const char* CLogHandler::convertEnum(LOGLEVEL level) { switch(level) { case L_OK: return "INFO "; break; case L_ERROR: return "ERROR"; break; case L_FATAL_ERROR: return "FATAL"; break; case L_INFO: return "INFO "; break; case L_WARN: return "WARN "; break; case L_DEBUG: return "DEBUG"; break; default: return "INFO "; break; } }und das funktioniert herrlich