Design-Frage Punktklasse
-
Danke fuer die schneller Antwort und die konstruktive Kritik!
Ist
assert (idx<=2);eigentlich aequivalent zu
#ifndef NDEBUG if (idx > 2) std::cerr << "Point::operator[] - idx error" << std::endl; #endif? Dann waere deine Schreibweise in der Tat eleganter.
Den zweiten Konstruktor habe ich entfernt. Die Schnittstelle will ich so minimal wie moeglich halten. Vermutlich werde ich sehr viele Punkte haben und schon aus diesem Grund sollte der Punkt nur das noetigste enthalten. Das fuehrt mich zu deinem dritten Kritikpunkt, naemlich das du
const T* const getData () const { return x; }ein wenig sinnlos findest. Ich habe mich hier fuer eine Methode entschieden, weil ich die Schnittstelle klein halten will. Aber ich ueberlege mir das vlt. noch mal.
Die Ableitung von AbstractPoint ist eigentlich nur wegen meines Design-Problems (siehe mein erster Beitrag). Meine eigentliche (nicht virtuelle) Basisklasse soll Point sein. Das Klassentemplate kann aber mit verschiedenen Typen instantiert werden. Damit habe ich verschiedene Punkttypen (std::vector< std::vector <???> >). Gibt es dafuer eine bessere Loesung?
-
Ich verstehe die Motivation, Zeiger und polymorphe Basisklassen einzusetzen, nicht ganz in diesem Fall.
Du könntest mal einen "Schritt zurück machen" und erklären, was Du damit eigentlich bezwecken willst. Immerhin heißt dieser Thread "Design-Frage". Das Thema schreit förmlich danach, dass Du das Problem beschreibst, was Du mit Deinem Design-Ansatz zu lösen verschst.
Gruß,
SP
-
Ich moechte Objekte beschreiben, welche aus Punkten bestehen. Es soll Objekte geben, die lediglich die Koordinaten haben (die von verschiedenen Datentypen sein koennen: double, float, int, ...). Die Punkte koennen aber auch zusaetzliche Eigenschaften haben. Dazu moechte ich Vererbung nutzen. Beispielsweise koennte ein Punkt einen Namen haben:
template <class T> class NamedPoint : public Point <T>oder eine Farbe, oder Materialeigenschaften tragen, ...
Ich habe daher Punkte von verschiedenen Typen. Fuer jeden Punkttyp existiert ein Vektor indem die Punkte gespeichert werden.
Beispiel:
std::vector<Point<double>*> dbl_pnt_vec; std::vector<Point<size_t>*> size_t_pnt_vec; std::vector<NamedPoint<size_t>*> named_size_t_pnt_vec; std::vector<ColoredPoint<float>*> colored_float_pnt_vec; ...Jetzt moechte ich all diese Vektoren in einem Vektor verwalten. Dazu benoetige ich ja eine Basisklasse, oder? Das ist die AbstractPoint-Klasse im ersten Post dieses Threads.
std::vector< std::vector< AbstractPoint* > > pnt_vec;Die Klasse AbstractPoint ist meiner Meinung nach etwas kuenstlich. Gibt es da bessere Loesungen? Ist mein Design vlt. falsch?
-
123_tom_dabei schrieb:
Die Schnittstelle will ich so minimal wie moeglich halten.
Das ist eine gute Idee, aber es gibt da ein paar Dinge zu beachten:
1. Minimal gut, minimalistisch schlecht. Es geht nicht darum, immer das Minimum zu finden, sondern eine gut ausgewogene Sache.
2. Ist deine Schnittstelle dadurch wirklich so klein? Vergiss nicht, dank dem dass du ein Array zurück gibst, gibst du eigentlich deine ganze interne Struktur bekannt und zurück. Das hat nichts mehr mit Kapselung zu tun und macht die Schnittstelle eigentlich grösser. Du schreibst zwar weniger, aber für den Anwender ist die Schnittstelle komplexer. Weniger schreiben heisst nicht, dass die Schnittstelle kleiner ist.123_tom_dabei schrieb:
Ich moechte Objekte beschreiben, welche aus Punkten bestehen. Es soll Objekte geben, die lediglich die Koordinaten haben (die von verschiedenen Datentypen sein koennen: double, float, int, ...). Die Punkte koennen aber auch zusaetzliche Eigenschaften haben. Dazu moechte ich Vererbung nutzen.
Eher die falsche Beziehung. Sowas ist doch keine is-a Beziehung. Sowas ist eine has-a Beziehung. Zum Beispiel deine NamedPoint Klasse, sie besteht aus einem Namen und einem Punkt.
123_tom_dabei schrieb:
Die Klasse AbstractPoint ist meiner Meinung nach etwas kuenstlich. Gibt es da bessere Loesungen? Ist mein Design vlt. falsch?
Wozu willst du alles in einen Vector werfen? Sowas ist meistens völlig unnötig. Halte lieber separate Listen, wenn die Objekte miteinander nix zu tun haben, was hier meiner Meinung nach der Fall ist.
Grüssli
-
Ich würde auch sagen dass das eher ein Fall für Aggregation als für Vererbung ist.
Point: T x, T y, PointProperties* properties (kann NULL sein)
PointProperties: std::string* name (kann NULL sein), Color* color (kann NULL sein) etc.Damit hast du einen zusätzlichen Zeiger pro Punkt, das ist zumindest nicht schlechter als wenn du die Punkt-Klasse polymorph machen würdest (dann hättest du nämlich einen vtable Zeiger statt des "properties" Zeigers).
-
Vielen Dank fuer die hilfreichen Antworten.
Ich habe das Klassentemplate erweitert:
/** class-template for Points * \param T the coordinate type * \param P the properties of the point (name, color, material, ...) */ template <class T, class P> class Point : public AbstractPoint, public P { ... };Mit der Klasse PropertyEmpty kann ich mir einen Punkt ohne weitere Eigenschaften erzeugen, mit der Klasse PropertyName habe ich einen Punkt mit Namen, usw.
Trotzdem bleibt die Frage: Gibt es eine Alternative zur Ableitung von AbstractPoint um die verschiedenen Vektoren in einem Vektor von Vektoren speichern zu koennen.
Eigentlich eine neue Frage: Kann man eine verschiedene Anzahl von Template-Argumenten uebergeben? Dann koennte man sich einen Punkt ganz flexibel mit
den benoetigten Eigenschaften, zum Beispiel Name, Farbe und ... durchPoint<T, PropertyName, PropertyColor, weitere Property-Klassen> pzusammenbauen.
Ansonsten muesste man fuer die Kombination von Eigenschaften ja eigene Property-Klassen schreiben, oder?
-
Bringt nicht viel, wenn du nicht auf unsere Fragen und Antworten eingehst, daher zitiere ich mich jetzt einfach mal selbst:
Dravere schrieb:
Eher die falsche Beziehung. Sowas ist doch keine is-a Beziehung. Sowas ist eine has-a Beziehung. Zum Beispiel deine NamedPoint Klasse, sie besteht aus einem Namen und einem Punkt.
Dravere schrieb:
Wozu willst du alles in einen Vector werfen? Sowas ist meistens völlig unnötig. Halte lieber separate Listen, wenn die Objekte miteinander nix zu tun haben, was hier meiner Meinung nach der Fall ist.
Grüssli
-
Ich möchte mich im wesentlichen meinen Vorrednern anschließen.
Die wesentliche Frage ist doch, was Du mit diesen Objekten voller Punkte machen möchtest.123_tom_dabei schrieb:
Ich moechte Objekte beschreiben, welche aus Punkten bestehen. Es soll Objekte geben, die lediglich die Koordinaten haben (die von verschiedenen Datentypen sein koennen: double, float, int, ...). Die Punkte koennen aber auch zusaetzliche Eigenschaften haben.
...
Gibt es da bessere Loesungen? Ist mein Design vlt. falsch?das beantwortet die Frage nicht. Was heißt 'beschreiben' und vor allem - wieseo und wofür?
Es ist keine gute Idee einen vector von vectoren zu bilden - das ist nachher recht umständlich beim Zugriff. Deine Beschreibung hört sich eher nach einem vector von Objekten an, wobei jedes Objekt wiederum einen vector aus Punkten beinhaltet.
Versuche mal ganz ohne Vererbung und ganz ohne Pointer in den vectoren aus zukommen.Und ganz konkret nochmal nachgefragt: was hast Du mit der Farbe oder dem Namen, der an einem Punkt hängt, später vor?
Sollen in einem einzelnen vector sowohl ein Punkt mit Farbe als auch ein Punkt mit Namen untergebracht sein?Gruß
Werner
-
Und auch noch als Nachtrag:
die Basisklasse 'AbstractPoint' hat bisher überhaupt keinen Nutzen, da sie für einen std::vector< AbstractPoint* > keine virtuellen Methoden (außer dem Destruktor) anbietet.123_tom_dabei, vllt. solltest du mal vom 'top-down-modell' ausgehen und die mögliche Benutzung des vectors beschreiben?
-
Ich will meine Motivation noch mal erklaeren. In einem bestehenden Programm gibt es eine Punkt-Klasse die abzueglich der Koordinaten 28 Attribute hat. Bisher hat jeder der eine zusaetzliche Eigenschaft des Punkts gebraucht hat diese einfach durch Aggregation (public!) dazu gefuegt. Nutze ich jetzt Aggregation habe ich ja wieder alle Eigenschaften in dieser riesigen Punkt-Klasse. Ich denke wenn der Nutzer meiner Klasse sich die Eigenschaften, die er benoetigt durch meine obigen Konstrukte selbst zusammenstellen kann, werden die Punkte deutlich kleiner.
Die Punkte werden zur Beschreibung von Polylinien genutzt. Eine Folge von Polylinien begrenzt eine Oberflaeche. Die Oberflaechen umschliessen Volumen.
Es gibt also Punkte die zu Polylinien gehoeren die vlt. eine Farbe haben sollen. Eine Flaeche koennte Materialeigenschaften haben, die mit einer bestimmten Farbe dargestellt werden. In der Rechnung werden die Materialeigenschaften benoetigt, zur Visualisierung die Farbe. Im Inneren eines Volumen haben die Punkte vlt. keine weiteren Eigenschaften. Das ist nur ein moegliches Szenario. Mir ist auch bewusst, dass ich die Eigenschaften meist besser den anderen geometrischen Objekten (Polyline, Flaeche, Volumen) zuordnen sollte. Ich kann aber nicht alles auf einmal aendern

Ihr meint also, ich soll auf Vererbung von den Eigenschaftsklassen verzichten und das durch die folgende Aggregation loesen?
/** class-template for Points * \param T the coordinate type * \param P the properties of the point (name, color, material, ...) */ template <class T, class P> class Point : public AbstractPoint { public: P properties; ... };Dann waere der Zugriff auf eine Eigenschaft umstaendlicher als bei Vererbung.
Aber nach wie vor brauche ich fuer die durch die Templateklasse erzeugten verschiedenen Typen einen Basistyp - egal ob ich die Punkte in Vektoren oder Listen verwende.
@Th69 (zu deinem Nachtrag)
Genau das gefaellt mir ja auch nicht, dass AbstractPoint in der Vererbungshierarchie einfach oben drauf gesetzt wird. Das war aber bisher die einzige Loesung die mir eingefallen ist - deshalb ja der Thread.