conversion operator erzeugt zuviele Interpretationen von operator ==
-
class string { public: string(const char*); operator const char*() const; friend operator==(const string& l, const char* r); } string ob1; char ob2[20]; if(ob1==ob2)... string ob3 if (ob1==ob3) ...Wenn ich Compiler wäre, würde ich sowohl ob2 als auch ob3 in const char* umwandeln, dann müsste es ja funktionieren...
Der Compiler müsste ja alle in Frage kommenden Vergleichsobjekte (also char* char[], const char*, const char[]) in const char* umwandeln können und damit den Vergleichsoperator aufrufen können.
Würde auch funktionieren, wenn es nicht den eingebauten char* == char* Operator geben würde^^Oder hab ich da was falsch verstanden? Jedenfalls kommt es mir so vor, als würde es komplett ohne casten gehen..??.?
-
Das Problem ist das man sehr schnell Fehler macht, weil man die ganzen Möglichkeiten die sich, aufgrund impliziter Konvertierung, ergeben garnicht überblicken kann. Die Anzahl der Möglichkeiten ist bei konstanten Typen geringer, es existieren aber immer noch genug die dumme Fehlerquellen sind. Das schlimme ist die Fehlersuche, du wirst bei einem großen Projekt fluchen wenn du so einen Fehler suchen musst und Tage deines Lebens verschwendest diesen zu finden!
grüße
-
Wenn ich Compiler wäre, würde ich sowohl ob2 als auch ob3 in const char* umwandeln, dann müsste es ja funktionieren...
Ja, denke ich auch. (Allerdings betrachte ich den operator == (string&, string&) als den für die Klasse typischen Operator und den
operator == (string&, char*) als sekundäre Anpassung an externe char*'s.)Würde auch funktionieren, wenn es nicht den eingebauten char* == char* Operator geben würde^^
Oder hab ich da was falsch verstanden?
Beim dem Satz oben bekomme ich schon den Eindruck, dass Du vielleicht etwas falsch verstanden hast. Der eingebaute operator == (char*, char*) ist ja das, was in den diskutierten Situationen immer vermieden werden muss. Ich weiss nicht ob Du string und char* zu sehr vermischt. Du hattest da einige nicht ganz richtigen Formulierungen wie:
Schließlich besteht die Klasse nur aus einem char*, ...
Für den string-vergleich spielt es in der Tat keine so grosse Rolle, dass die Klasse auch noch andere Elemente enthält.
In meinen Beispielen habe ich statt des notwendigen Codes für den Vergleich immer nur return 0/1 geschrieben, nur um etwas kompilierbares zu haben. Ich hoffe, das hat niemanden verwirrt.
-
hgf schrieb:
In meinen Beispielen habe ich statt des notwendigen Codes für den Vergleich immer nur return 0/1 geschrieben, nur um etwas kompilierbares zu haben. Ich hoffe, das hat niemanden verwirrt.
Glaube nicht, dass du jemanden verwirrt hast

hgf schrieb:
Allerdings betrachte ich den operator == (string&, string&) als den für die Klasse typischen Operator [...]
Im Prinzip ja, aber IMO bräuchte man als zweiten Parameter ja gar kein string&, wenn der sowieso in ein const char* gecastet wird (werden kann). Deckt man halt ein größeres Feld mit dem Operator ab

hgf schrieb:
Für den string-vergleich spielt es in der Tat keine so grosse Rolle, dass die Klasse auch noch andere Elemente enthält.
Ich dachte immer, der Compiler benutzt die eingebauten Operatoren, wenn die Klasse nur aus einem Typ besteht...?
hgf schrieb:
Der eingebaute operator == (char*, char*) ist ja das, was in den diskutierten Situationen immer vermieden werden muss.
Das wollte ich ja auch gar nicht! Mir ging es ja nur um den Operator const char*. Also auch operator== (const char*, const char*). Gilt da das auch noch mit dem Vermeiden? Wenn ja, warum?
PS: Danke für die Antwort

-
Badestrand schrieb:
Das wollte ich ja auch gar nicht! Mir ging es ja nur um den Operator const char*. Also auch operator== (const char*, const char*). Gilt da das auch noch mit dem Vermeiden? Wenn ja, warum?
Weil auch dieser nur Zeiger vergleicht, und nicht Inhalte.
-
Badestrand schrieb:
hgf schrieb:
Allerdings betrachte ich den operator == (string&, string&) als den für die Klasse typischen Operator [...]
Im Prinzip ja, aber IMO bräuchte man als zweiten Parameter ja gar kein string&, wenn der sowieso in ein const char* gecastet wird (werden kann). Deckt man halt ein größeres Feld mit dem Operator ab

Nein, eine String-Klasse hat üblicherweise auch einen Ctor, der (const) char* entgegennimmt - und dann ist es letztlich egal, ob die Umwandlung von char* nach string bei der Parameter-Übergabe passiert oder im Inneren des op==.
hgf schrieb:
Für den string-vergleich spielt es in der Tat keine so grosse Rolle, dass die Klasse auch noch andere Elemente enthält.
Ich dachte immer, der Compiler benutzt die eingebauten Operatoren, wenn die Klasse nur aus einem Typ besteht...?
Falsch gedacht. Der Compiler benutzt die eingebauten Operatoren immer, wenn er in der Lage ist, deine Klasse in einen Build-in Typ umzuwandeln (und nichts "besseres" zur Verfügung steht). Sprich: Sobald deine Klasse 'string' einen op char* anbietet, denkt er zumindest darüber nach, die Vergleiche auf char*-Ebene durchzuführen.
-
LordJaxom schrieb:
Badestrand schrieb:
Das wollte ich ja auch gar nicht! Mir ging es ja nur um den Operator const char*. Also auch operator== (const char*, const char*). Gilt da das auch noch mit dem Vermeiden? Wenn ja, warum?
Weil auch dieser nur Zeiger vergleicht, und nicht Inhalte.
Wenn ich den Operator überschreibe (bzw halt op== string&, const char*), vergleicht er ja eben nicht mehr die Zeiger. Sonst bräuchte ich den Operator ja nicht...
CStoll schrieb:
Nein, eine String-Klasse hat üblicherweise auch einen Ctor, der (const) char* entgegennimmt - und dann ist es letztlich egal, ob die Umwandlung von char* nach string bei der Parameter-Übergabe passiert oder im Inneren des op==.
Achso, na gut... Aber verbraucht die Umwandlung in ein (bzw Erstellung eines) string-Objekt(es) dann nicht mehr Laufzeit als ein Cast? Den Cast könnte man ja inlinen, dann muss ja nur das Objekt direkt auf den Stack gepusht werden. Wenn das Objekt erstellt wird, muss es ja auf dem Stack erzeugt werden (was ja nicht viel kostet), aber dann wird der Konstruktor aufgerufen, der String kopiert, übergeben und dann der Destruktur ausgeführt... Das dürfte der Compiler ja eigentlich nicht weg-optimieren.
Und was meinst du mit "Umwandlung [...] im Inneren des op=="? Im Inneren des op musst du ja nicht nach string umwandeln. In dem Fall kann man doch einfach strcmp aufrufen oder eine ähnliche Funktion durchlaufen lassen
Nach wie vor: Ich sehe immer noch keinen Nachteil, in eine String-Klasse den operator const char* zu implementieren :xmas2:
-
Badestrand schrieb:
LordJaxom schrieb:
Badestrand schrieb:
Das wollte ich ja auch gar nicht! Mir ging es ja nur um den Operator const char*. Also auch operator== (const char*, const char*). Gilt da das auch noch mit dem Vermeiden? Wenn ja, warum?
Weil auch dieser nur Zeiger vergleicht, und nicht Inhalte.
Wenn ich den Operator überschreibe (bzw halt op== string&, const char*), vergleicht er ja eben nicht mehr die Zeiger. Sonst bräuchte ich den Operator ja nicht...
Du hast theoretisch vier verschiedene Kombinationsmöglichkeiten für den Vergleich - String==String, String==char*, char*==String und char*==char*. Die letzte Kombination kannst du nicht beeinflussen, die ersten beiden fängst du mit den eigenen Operatoren ab - die dritte Kombination bereitet Probleme, weil du sie nicht implementiert hast (und für den Compiler sind die Alternativen "ersten Parameter per Ctor in String umwandeln" und "zweiten Parameter per Cast-Operator in char* umwandeln" gleich gut).
Achso, na gut... Aber verbraucht die Umwandlung in ein (bzw Erstellung eines) string-Objekt(es) dann nicht mehr Laufzeit als ein Cast? Den Cast könnte man ja inlinen, dann muss ja nur das Objekt direkt auf den Stack gepusht werden. Wenn das Objekt erstellt wird, muss es ja auf dem Stack erzeugt werden (was ja nicht viel kostet), aber dann wird der Konstruktor aufgerufen, der String kopiert, übergeben und dann der Destruktur ausgeführt... Das dürfte der Compiler ja eigentlich nicht weg-optimieren.
Erst solltest du dafür sorgen, daß dein Programm funktioniert, danach kannst du dir überlegen, wo du Optimierungen benötigen könntest

Und was meinst du mit "Umwandlung [...] im Inneren des op=="? Im Inneren des op musst du ja nicht nach string umwandeln. In dem Fall kann man doch einfach strcmp aufrufen oder eine ähnliche Funktion durchlaufen lassen

Ich war von meinem üblichen Vorgehen ausgegangen - und da versuche ich normalerweise, Code-Dopplungen zu vermeiden.
Nach wie vor: Ich sehe immer noch keinen Nachteil, in eine String-Klasse den operator const char* zu implementieren :xmas2:
Der Punkt ist: Dieser Operator wird überall eingesetzt, wo der Compiler denkt, daß er passen könnte - selbst wenn dabei im konkreten Anwendungsfall absoluter Müll rauskommt. Und diese Situationen wirst du nur schwer überblicken können (z.B. in einer if-Bedingung (
if(str)..- Vergleich "str==""" vergessen - egal) oder bei delete (String* pstr=new String;...;delete*pstr;- * zu viel - egal) - diese "egal"-Situationen schluckt der Compiler anstandslos, aber im laufenden Betrieb bekommst du Probleme). Eine Methode ala c_str() wird dagegen nur dann verwendet, wenn du es explizit angibst.
-
Badestrand schrieb:
Nach wie vor: Ich sehe immer noch keinen Nachteil, in eine String-Klasse den operator const char* zu implementieren :xmas2:
Dann hast du wohl nich richtig zugehört, bzw willst es einfach nicht verstehen.
-
Zugehört hab ich jedenfalls

Werde ne Weile drüber nachdenken, auf jeden Fall ein dickes Danke für die Argumente und Geduld!