Stringklasse,operatorüberladung...arghl
-
bluecode schrieb:
@Shade: Wieso sollte operator+ kein Member sein?
konsistenz.
int+int == int
da kann der op+ technisch gesehen member sein. aber bei
int+float == floatkann er es nicht mehr vernünftig. da ist er global wesentlich besser.
und ob
int+int==int
member oder global ist, ist egal.also lieber alles global, dann ist alles schön beisammen.
der op+ als member hat ja einen lustigen pitfall:
Foo operator+(Foo const& other) { Foo temp(other); temp+=*this; return temp; }
finde den fehler
-
Was mich wundert ist, dass Shade noch gar nicht auf ECP11 eingegangen ist. Naja, dann fass ich es mal zusammen.
Beachte folgenden Fall:
MeinString a("foo"); MeinString b = a; // Copy-Konstruktor wird aufgerufen
Wie du siehst, wird der Copy-Konstruktor aufgerufen. Den hast du aber nicht definiert. Deshalb wird der Standard-Copy-Konstruktor erzeugt und aufgerufen, der jede einzelne Member-Variable kopiert. Weil du einen Zeiger für den String benutzt, wird die Adresse, auf die a.chr zeigt, nach b.chr kopiert, womit a und b auf dieselbe Stelle zeigen. Wenn jetzt der Destruktor von a aufgerufen wird (btw: den hast du noch gar nicht, einfaches delete [] chr;), zeigt b.chr auf eine ungültige Stelle.
Dasselbe gilt übrigens auch beim Zuweisungsoperator:
MeinString a("foo"); MeinString b = "bar"; b = a;
Hier gibt es aber noch ein weiteres Problem. b.chr hat vorher auf "bar" gezeigt, und der Wert von b.chr wird einfach mit dem Wert von a.chr überschrieben, sodass nie ein delete[] auf "bar" ausgeführt wird.
Und noch etwas tückisches beim Copy-Konstruktor:
void MyFunction(MeinString foo) {} MeinString bar = "Tach auch."; MyFunction(bar);
Der Parameter von MyFunction wird by value übergeben, sodass der Copy-Konstruktor für foo mit dem Parameter bar aufgerufen wird. Das selbe Spielchen wie gehabt: bar.chr und foo.chr zeigen auf dieselbe Speicherstelle. Jetzt lebt foo aber ziemlich kurz und es wird beim Verlassen der Funktion schon wieder der Destruktor aufgerufen, der ein delete[] chr; ausführt, womit bar auf ungültigen Speicher zeigt.
-
Sorry hab grad wenig zeit...hab nur shades gelesen...
Aber genauer nachgefragt: wie muss den den + operator aussehen das er funktioniert?
Das gleiche beim ==?denn
static bool isequal(MeinString &s1,MeinString &s) { return !strcmp(s1.chr, s.chr); } //und bool operator==(MeinString &rhs,MeinString &lhs) { return MeinString::isequal(rhs,lhs); }
funktionieren nicht!
-
Man.bloed schrieb:
funktionieren nicht!
kleiner tipp: nie eine Fehlerbeschreibung geben, wir lieben ein gutes Rätsel
-
hab doch schon ganz am anfang gesagt was nich geht:
Operator +:MeinString str("hallo"); MeinString str2("test"); MeinString str4("hallo"); MeinString str3=str+str2;
da wird nicht nur aus str3 hallotest, sondern auch aus str (aber str soll sich ja nich verändern)
Und equal:
da liefert immer false zurück, ausser wenn ich die gleichen Instanzen vergleiche:
str==str=true;
str==str4=false;beide haben aber selben inhalt (hallo)
-
Man.bloed schrieb:
hab doch schon ganz am anfang gesagt was nich geht:
Operator +:MeinString str("hallo"); MeinString str2("test"); MeinString str4("hallo"); MeinString str3=str+str2;
da wird nicht nur aus str3 hallotest, sondern auch aus str (aber str soll sich ja nich verändern)
Und was erwartest du, wenn du
char* chr1 = strcat(chr,rhs.chr);
schreibst? Ich hoffe dir ist klar, dass du damit die aktuelle Instanz veränderst. Mit const-correctness wäre das übrigens nicht passiert.
Aber um's kurz zu machen, Shade hat ja schon ein Beispiel gepostet, wie das im Prinzip aussieht. Du erstellst eine temporäre Instanz, hängst den rechten Operanden ran und gibst diese by-value zurück. Und mit entsprechendem copy-ctor funktioniert das dann auch problemlos.const MeinString operator +(const MeinString& lhs, const MeinString& rhs) { MeinString tmp(lhs); tmp += rhs; return tmp; }
Fehlt nur noch der entsprechende Assignment-Operator, aber das wirst du schon hinbekommen. Der Funktionsrumpf sieht wie folgt aus
MeinString& operator +=(const MeinString& rhs) { //... return *this; }
Auf diese Art und Weise lassen sich übrigens alle verknüpfenden Operatoren (+,-,*,/,%,&,|,^) implementieren.
edit:
Rückgabewert von operator + korrigiert.
-
Shade Of Mine schrieb:
Foo operator+(Foo const& other) { Foo temp(other); temp+=*this; return temp; }
Foo operator+(Foo const& a,Foo const& b) { Foo temp(a); temp+=b; return temp; }
ok
-
Shades Beispiel war aber innerhalb der Klasse. Bin mir zwar jetzt nicht ganz sicher, was er wollte (bis auf des fehlende const). Aber er macht in Wirklichkeit b + a, obwohl es a + b sein müsste.
-
groovemaster schrieb:
Shades Beispiel war aber innerhalb der Klasse. Bin mir zwar jetzt nicht ganz sicher, was er wollte (bis auf des fehlende const). Aber er macht in Wirklichkeit b + a, obwohl es a + b sein müsste.
Ja, ich wollte auf das const hinaus.
das mit b+a war ein Fehler von mir
hab nicht genau nachgedacht und nach sturer gewohnheit den 1. parameter als lhs angenommen und ohne nachzudenken wurde dann this zum rhs.
dumm von mir
-
Wenn schon const-correctnes dann auch richtig:
const Foo operator+(Foo const& a,Foo const& b) { Foo temp(a); temp+=b; return temp; }
-
Eine lokale Variable darf doch eh nicht verändert ewrden oder seh ich da was falsch?
-
hm...irgendwie bekomm ich das nich hin!
Also die operatoren ausserhalb der klasse?Wenn ja, wie greife ich auf die private objekte zu? (also mein charzeiger)?
-
Schau dir mal das Schlüsselwort friend an, dies ermöglicht es dir auch auf private Elemente außerhalb der Klasse zuzugreifen.
http://www.cpp-tutor.de/cpp/le12/le12_04.htm#logisch
PS: Warum hat es hier solange gedauert, bis mal jemand auf die eigentliche Frage von Man.bloed eingegangen ist?
-
danke....
nun habe ich aber gehört...friend soll man nicht nehmen?
-
Shade Of Mine schrieb:
das mit b+a war ein Fehler von mir
hab nicht genau nachgedacht und nach sturer gewohnheit den 1. parameter als lhs angenommen und ohne nachzudenken wurde dann this zum rhs.
Gebs zu, du hast absichtlich 2 pitfalls eingebaut.
Man.bloed schrieb:
nun habe ich aber gehört...friend soll man nicht nehmen?
Keine Ahnungen wo du das gehört hast. Aber da hat der Autor sicher etwas übertrieben. Natürlich sollte man friend mit Bedacht verwenden, aber vollkommen darauf zu verzichten, ist Unsinn. Gerade bei solchen Operatoren sind sie hilfreich, und du brichst damit ja auch nicht den bestehenden Klassenschutz.
-
Michael E. schrieb:
Eine lokale Variable darf doch eh nicht verändert ewrden oder seh ich da was falsch?
Minimal Beispiel:
class Foo { public: Foo(): a_(0) {} Foo(int a): a_(a) {} Foo& operator+=(Foo const& a) { this->a_ += a.a_; return *this; } private: int a_; }; Foo operator+(Foo const& a, Foo const& b) { Foo temp(a); temp+=b; return temp; } int main() { Foo a(1), b(2), c(3); a + b = c; // geht int d(1), e(2), f(3); d + e = f; // geht nicht!! }
Alleine schon um den gleichen Effekt wie bei den Ints zu haben, sollte man den Rückgabewert const machen.