complex-Klasse - so ok? Stil und Coding -Tips erwünscht!
-
Hmm, wenn du schon immer alles über toPolar umrechnest, dann kannst du die Polarkoordinaten doch auch für die Berechnungen nutzen
z1*z2=r1*r2*exp(i*(phi1+phi2))
z1/z2=r1/r2*exp(i*(phi1-phi2))
und dann wieder zurück in karthesische Koordinaten...Ansonsten schließe ich mich Gregors Meinung an.
-
ctemp.real() = ...
ich bin der Meinung das man sowas nicht nutzen sollte.
-
Danke! Ihr habt Recht - wieder mal ein klarer Fall für "weniger ist manchmal mehr". Das getAbs hab ich auch nachträglich mit den beiden Variablen abs. und arg. eingebaut und die alte Methode glatt übersehn.
inline double& Complex::real()
soll ich lieber ein Methode "setReal" machen? Dachte per Referenz ist das schick.
-
Gumble schrieb:
Hätte gern Tipps zu dem Quelltext hier
Noch ein ganz wertvoller Tipp:
Nicht selber schreiben, sondern std::complex benutzen. Das ist fertig, performant und fehlerfrei.Aber zum Üben ist sowas natürlich trotzdem sinnvoll.
MfG Jester
-
Ich finde du solltest Membervariablen kenntlich machen.
entweder mit _re oder m_re oder so. Damit sie von Funktionsvariablen
unterscheidbar sind. Auch wenn du sogutwie nur Membervariablen hast, können andere
schneller reinfinden.Sorry, zu schnell gelesen. War schon dran.
inline double& real();
Hier mit machts du private Membervaribale public
//entweder inline double real() const; //oder inline const double& real() const ;
-
ich finde die set-Funktionen für Real- und Imaginärteil völlig überflüssig. Sowas braucht man doch nicht. Bei double gibts schließlich auch keine Funktion, mit der ich den Exponenten verändern kann.
-
idefix schrieb:
Ich finde du solltest Membervariablen kenntlich machen.
entweder mit _re oder m_re oder so. Damit sie von Funktionsvariablen
unterscheidbar sind. Auch wenn du sogutwie nur Membervariablen hast, können andere
schneller reinfinden.Ist das mit dem Unterstrich Konvention? Hab keine Ahnung.
idefix schrieb:
inline double& real();
Hier mit machts du private Membervaribale public
//entweder inline double real() const; //oder inline const double& real() const ;
ich brauch ja ne Schnittstelle nach außen - denn die operator / und * und >> müssen ja die Membervariablen ändern können.
abs und arg hab ich schon rausgeschmissen, genauso wie toPolar. Die Funktionen getArg, getArg_rel und getAbs reichen völlig.
-
idefix schrieb:
Ich finde du solltest Membervariablen kenntlich machen.
entweder mit _re oder m_re oder so. Damit sie von Funktionsvariablen
unterscheidbar sind. Auch wenn du sogutwie nur Membervariablen hast, können andere
schneller reinfinden.Ich halte das nicht für hilfreich. Das ist IMHO Geschmackssache. Einige machen die Member nochmal extra kenntlich, andere nicht. Ich halte es für wichtiger, dass die Methoden etc. kurz und übersichtlich sind. Das ist hier wohl gegeben. Mir würde es deshalb nichts bringen, wenn die Member noch irgendein Pre- oder Postfix haben. Ich sehe auch so sofort, was ein Member ist und was nicht.
Wichtiger fände ich es, dass die Variablennamen aussagekräftiger gewählt werden. Hier ist zwar klar, wofür eine Variable "re" steht, bei einer anderen Klasse kann so eine Abkürzung aber schon nicht mehr so klar sein.
-
Aber wenn irgendwie markieren, dann nicht _ an den Anfang, das ist Vorbehalten für STL-Implementierer und Compiler-Bauer.
MfG Jester
-
Gumble schrieb:
#include <iostream> #include <cmath>
Statt <iostream> wäre, glaube ich, <iosfwd> besser, weil <iostream> nur dafür zuständig ist, dass man auf die vier (bzw. acht) Standardstreams zugreifen kann, <iosfwd> aber istream und ostream deklariert. In der Complex.cpp musst du dann <istream> und <ostream> inkludieren, außerdem würde ich <cmath> auch dahin verschieben.
Complex(const Complex& c); Complex& operator= (const Complex& c); ~Complex();
Was ist an den automatisch generierten Versionen hier auszusetzen? Die haben den Vorteil, dass sie in "normalen" Klassen immer das richtige tun und man beim Hinzufügen eines Members nichts übersehen kann.
inline double real() const; inline double& real(); inline double imag() const; inline double& imag();
inline hilft nicht viel, wenn die Definition der Funktion in einer .cpp-Datei versteckt ist. Ja, manche Linker können auch diese Grenze teilweise überwinden, aber hier würde ich einfach schreiben:
double& real() { return re; } // Implizit inline, weil direkt in der Klasse definiert
Überhaupt muss man "inline" nur noch verwenden, um kleine Funktionen direkt in den Header schreiben zu können (d.h. keine Linkerprobleme zu bekommen), Compiler entscheiden alleine schon ganz gut, was sie inlinen.
Complex& Complex::operator= (const Complex& c) { if (this == &c) return *this; ... }
Wozu der Selbstzuweisungstest? Der erspart nur im Ausnahmefall der Selbstzuweisung ein paar Variablenzuweisungen, ansonsten macht er die Zuweisung sogar langsamer. IMHO braucht man den Selbstzuweisungstest nur sehr selten.
Und print() kann IMHO raus, dafür gibt es op<<
-
Statt <iostream> wäre, glaube ich, <iosfwd> besser, weil <iostream> nur dafür zuständig ist, dass man auf die vier (bzw. acht) Standardstreams zugreifen kann, <iosfwd> aber istream und ostream deklariert. In der Complex.cpp musst du dann <istream> und <ostream> inkludieren, außerdem würde ich <cmath> auch dahin verschieben.
hm, dann kann ich nimmer auf std::cout zugreifen und er wirft mir noch ein paar Fehler wegen '<<'
Dachte immer, ich steck alle includes in den Header - was ist nun usus?Complex(const Complex& c); Complex& operator= (const Complex& c); ~Complex();
Was ist an den automatisch generierten Versionen hier auszusetzen? Die haben den Vorteil, dass sie in "normalen" Klassen immer das richtige tun und man beim Hinzufügen eines Members nichts übersehen kann.
Hab ich wirklich Nachteile wenn ich das selber definier?
inline double real() const; inline double& real(); inline double imag() const; inline double& imag();
inline hilft nicht viel, wenn die Definition der Funktion in einer .cpp-Datei versteckt ist. Ja, manche Linker können auch diese Grenze teilweise überwinden, aber hier würde ich einfach schreiben:
Ok, inline hab ich rausgeschmissen - dachte es wär gut.
double& real() { return re; } // Implizit inline, weil direkt in der Klasse definiert
Überhaupt muss man "inline" nur noch verwenden, um kleine Funktionen direkt in den Header schreiben zu können (d.h. keine Linkerprobleme zu bekommen), Compiler entscheiden alleine schon ganz gut, was sie inlinen.
soll ich nur eine Funktion (die mit der Referenz als Rückgabe) verwenden? Gibt das irgendwelche Vor- oder Nachteile?
Complex& Complex::operator= (const Complex& c) { if (this == &c) return *this; ... }
Wozu der Selbstzuweisungstest? Der erspart nur im Ausnahmefall der Selbstzuweisung ein paar Variablenzuweisungen, ansonsten macht er die Zuweisung sogar langsamer. IMHO braucht man den Selbstzuweisungstest nur sehr selten.
Meister Meyers aus dem Effektiv C++ Buch hat das doch empfohlen, also lass ich es lieber so zur sicherheit
Und print() kann IMHO raus, dafür gibt es op<<
und weg damit
Danke nochmal für die Tips!
-
Gumble schrieb:
hm, dann kann ich nimmer auf std::cout zugreifen und er wirft mir noch ein paar Fehler wegen '<<'
Von std::cout muss deine Klasse ja auch nichts wissen
Wenn du an anderer Stelle cout/cin etc. brauchst, ist <iostream> dafür der richtige Header.
Dachte immer, ich steck alle includes in den Header - was ist nun usus?
Am besten so wenig #includes wie möglich im Header. Mit Vorausdeklarationen und dem "pimpl-Idiom" kann man da sogar eine Wissenschaft für sich draus machen, damit größere Projekte schneller kompilieren und seltener neu kompiliert werden müssen, wenn sich Header ändern.
Hab ich wirklich Nachteile wenn ich das selber definier?
Du musst sie halt erstmal alle tippen. Danach gilt: Code, den man nicht tippt, muss man nicht warten
Als einziger direkter Nachteil fällt mir hier nur ein, dass die automatisch generierten Versionen inline und dadurch vermutlich schneller wären (vor allem der Destruktor), wenn der Linker das nicht merkt und selber gerade biegt.
soll ich nur eine Funktion (die mit der Referenz als Rückgabe) verwenden? Gibt das irgendwelche Vor- oder Nachteile?
Nein, auf jeden Fall brauchst du zwei Funktionen: Eine, mit der man den Wert ändern kann und eine, mit der man den Wert einer "const Complex" auslesen kann. Das finde ich schon gut, wie es ist.
Meister Meyers aus dem Effektiv C++ Buch hat das doch empfohlen, also lass ich es lieber so zur sicherheit
Hm ja. Aber überleg mal, wofür der in EffC++ vermutlich gut war und warum das hier nicht zutrifft