Viele private Funktionen in Klasse schlechter Stil??
-
Killerqueen schrieb:
gibt es da vielleicht Tricks?

Was mir manchmal hilft: Einfach in einem Kommentar über die Klasse schreiben, was sie macht. Wenn ein "und" im Kommentar vorkommt, ist's Zeit zum Aufspalten
Man sagt "Pro Klasse eine Aufgabe" (nicht zu verwechseln mit "Pro Aufgabe eine Klasse") und ob sie noch mehr macht, merkt man (ok, ich zumindest) oft erst beim Erklären.
-
Killerqueen schrieb:
Und was mache ich wenn es keine logische Aufteilung gibt?
Meistens ergibt sich so eine mit der Zeit. Du musst dir überlegen, was man zusammenfassen könnte, was ähnliche Funktionalität hat, was voneinander abhängig ist. Gut funktioniert es auch, wenn du in "Objekten" denkst (hier wären das eben z.B. "Hund" und "Astronaut"). Sobald ein "Objekt" einen eigenen Status hat und du merkst, mehrere Variablen zur Beschreibung dieses Zustands zu benötigen, kann sich eine Auslagerung lohnen.
-
Okay ... danke Leute
Ich werd ein bisschen experimentieren.Aber was ist der Unterschied zwischen
Eine Klasse/Aufgabe
Eine Aufgabe/Klasse?

-
Das ist mehr so ein Grundsatz als wirklich wörtlich gemeint.
Für eine Aufgabe können ruhig mehrere Klassen zuständig sein, kommt eben drauf an, wie gross die Aufgabe ist. Meistens ist es doch so, dass diese in Teilaufgaben zerlegt werden kann, für welche wiederum einzelne Klassen zuständig sind.
Hingegen sollte es eher nicht vorkommen, dass eine Klasse mehrere Aufgaben übernimmt, die eigentlich nichts miteinander zu tun haben.
-
Killerqueen schrieb:
Das kling gut

Und was mache ich wenn es keine logische Aufteilung gibt? Also bei Hund Astronaut etc ist es ja noch recht eindeutig .... gibt es da vielleicht Tricks?
Entschuldige meine Einfallslosigkeit! Mir fällt gerade kein passendes Beispiel ein.Du liest Dir die Spielregeln durch und nimmst die Begriffe raus, das werden die Klassen. Naja, so ungefähr. Es wäre gut, wenn Du es mal eine Weile lang übertreiben würdest, also zu viele zu kleine Klassen machen. Wenn DU dann beide Welten kennst, schlägst Du einen gesunden Mittelweg ein. Der wird aber "Ein Zweck - eine Klasse!" als wesentliches Merkmal immer behalten.
Ach ja, und alle Generalisierungen sind falsch. Egal, was Du beim Programmieren dogmatisch durchziehst, es wird suboptimal werden. Experimentiere rum und mach am Ende das, was zu den wenigsten Fehlern und Schreibblockaden führt.
-
Super!
Aber wenn ich so viele Klassen verwende kann es doch unter Umständen vorkommen dass diese keine member-Daten enthalten?
Sind das dann schon zu viele Klassen?
Ist so eine Klasse generell sinnvoll?
-
Killerqueen schrieb:
Ist so eine Klasse generell sinnvoll?
Nein, meistens eigentlich nicht. Wenn die Klasse nur Funktionen anbietet, können diese normalerweise auch ebenso gut global sein (unter Umständen in einem Namensraum). Denn eine Instanz von so einer Klasse repräsentiert meistens nichts.
(Ausnahmen wie zum Beispiel in der Metaprogrammierung gibt es natürlich immer, aber die sind hier nicht gross von Bedeutung.)
-
(Ausnahmen wie zum Beispiel in der Metaprogrammierung gibt es natürlich immer, aber die sind hier nicht gross von Bedeutung.)
Es gibt nochmal eine Ausnahme, welche mir nicht unwichtig erscheint.
Na, was hat Funktionen, aber keine Datenmember? - Die kennen wir doch alle.
Genau. Abstrakte Basisklassen.
Das sind jetzt weniger Klasse im Sinne des TO's, aber imo dennoch nicht ausser Acht zu lassen.
-
Stimmt, hab ich völlig vergessen, interfacemässige Klassen. Danke für den Nachtrag.

-
So nun noch eine konkrete Frage:
Ich habe für eine member-Funktion eine Hilfsklasse definiert die 2 Zeiger managet.
Meine Funktion braucht als ARgument eine Refernez vom eigenen Typ:
bool raumfaehre::kollidiere(raumfaehre&);
Daher ist Pro raumfaehre eine Hilfsklasseninstanz nötig.<b>Ist es sinnvoll die Funktionalität in die Klasse raumfaehre zu packen und dabei diese um 2 Zeiger schwerer zu machen, welche nur für die eine Funktion und ihrer Unterfunktionen benötigt werden?</b>
Oder soll ich ganz auf Komfort setzen und jede Hilfsklasse per member varible auf eine raumfaehre beziehen:
Also statt:
bool raumfaehre::kollidiere(raumfaehre& raumfaehreB) { kollisionshelferA.berechne_bahn( *this ); kollisionshelferB.berechne_bahn( raumfaehreB ); //oder kollisions_helfer_t kollisionshelferA(this); kollisions_helfer_t kollisionshelferB(&raumfaehreB); kollisionshelferA.berechne_bahn(); //... }Ich brauche für die Aufgabe bestmögliche Performance!
Oder ist sowas eigendlich egal?!

-
Wenn bei der Kollision beide beteiligten Objekte gleich behandelt werden (es also keine Rolle spielt, ob A mit B kollidiert oder B mit A), würde ich eher eine globale Funktion als eine Memberfunktion nehmen:
void kollidiere(raumfaehre& a, raumfaehre& b);Zu deinen Kollisionshelfern: Da glaube ich, nicht ganz alles verstanden zu haben. Sind die global oder woher kennt sie die Funktion? Ist eine Raumfähre immer an einen Kollisionshelfer (z.B. über einen Zeiger) gebunden? Oder was für eine Beziehung (auch semantisch, nicht nur technisch) gibt es da?
-
Nun, die beiden Helfer werden innerhalb der Kollisionsfunktion lokal instanziiert.
Bei der Kollision wird jedes Polygon von Fähre A mit B getestet ob sie sich schneiden/berühren.
Dabei brauche ich 2 Zeiger auf die Kanten der Polygone, welche das gegnerische Polygon berührt oder schneidet..... jedenfalls muss viel mit den Zeigern hantiert werden darum habe ich eine extra Klasse dafür erstellt....Gegen die globale Funktion würde ich folgendes einwenden:
da sie exzessiv raumfaehren-Daten benötigt müsste ich sie als friend deklarieren was ich irgendwie hässlich finde
-
Killerqueen schrieb:
Gegen die globale Funktion würde ich folgendes einwenden:
da sie exzessiv raumfaehren-Daten benötigt müsste ich sie als friend deklarieren was ich irgendwie hässlich finde
Wahrscheinlich hast du noch keine richtige Schnittstelle für deine Raumfähren eingerichtet.
friendsollte nicht nötig sein, wenn man Get-/Set-Funktionen zur Verfügung stellt. Meist ist es auch sicherer und besser wartbar, wenn von aussen über Funktionen zugegriffen wird. Zum Beispiel kannst du dann Zugriffe mitloggen.Und zu den exzessiven Daten: Du musst ja nicht Dutzende von Funktionen anbieten. Eine Idee wäre eine kleine Struktur, zum Beispiel
CollisionData, die für die Kollision wichtige Attribute zusammenfasst.
-
Hmmm ...
... mir fällt gerade ein:
Nach einer Kollision bleibt nur eine Fähre übrig also muss die zweite ohnehin deletet werden. Vielleicht ist dann eine nicht-globale Lösung besser?Aber bei all dem bleibt dann noch das Problem mit meiner Hilfsklasse!!!!
Diese behinhaltet nämlich jeweils 2 KANTEN eines Polygons und muss lauter für die Kollision spezifische Sachen machen ....
-
Killerqueen schrieb:
Vielleicht ist dann eine nicht-globale Lösung besser?
Nein,
a.kollidiere(b)bleibt ja nach wie vor das Gleiche wieb.kollidiere(a). Darum geht es eigentlich. Wenn die Funktion nicht symmetrisch wäre, also zum Beispiel immer die übergebene Raumfähre zerstört würde, wäre das wieder etwas anderes.Du sagst ja auch nicht "b wird von a kollidiert". Entweder "a und b kollidieren" oder "a kollidiert mit b", bei letzterem könnte man aber ebenso gut "b kollidiert mit a" sagen. Ich habe hier natürlich vorausgesetzt, dass die Semantik wirklich gleich bleibt, wenn man die Argumente vertauscht.
Killerqueen schrieb:
Aber bei all dem bleibt dann noch das Problem mit meiner Hilfsklasse!!!!
Diese behinhaltet nämlich jeweils 2 KANTEN eines Polygons und muss lauter für die Kollision spezifische Sachen machen ....
Aber eben, kannst du die Schnittstelle nicht entsprechend anpassen? Zum Beispiel so:
struct physikdaten { // physikalische Dinge wie Position, Geschwindigkeit, ... // halt welche Eigenschaften für Kollision relevant sind. }; class raumfaehre { public: const physikdaten& get_kollisionsdaten() const; void set_kollisionsdaten(const physikdaten& daten); private: physikdaten meine_physik; }; class kollisionshelfer { public: kollisionshelfer(raumfaehre& bezugsobjekt); void berechne_schaden(); void schleudere_astronauten_ins_all(); private: raumfaehre& meine_faehre; };Nur so ein Vorschlag, ich weiss zu wenig Konkretes über dein Design. Intern könnte der Kollisionshelfer dann auf die Getter und Setter der Raumfähre zugreifen.