CProperty Get() und Set()
-
Ich bin mir nicht sicher, ob ich deine Absicht genau verstanden habe. Properties gibts in C#, aber nicht in C++.
Du möchtest also ein Get/Set-Paar für gewisse Variablen automatisch erstellen? Ganz automatisch geht nicht. Du könntest Makros verwenden, aber das würde ich nicht tun. Die Schnittstelle wird dadurch verschleiert und allfällige Fehler sind sehr mühsam zu finden.
Normalerweise schreibt man Setter und Getter von Hand. Aber natürlich nur für diejenigen Attribute, die nach aussen überhaupt eine Eigenschaft der Klasse repräsentieren.
-
Nexus schrieb:
Ich bin mir nicht sicher, ob ich deine Absicht genau verstanden habe. Properties gibts in C#, aber nicht in C++.
Das hab ich bereits herausgefunden, dass in C++ sowas per Default nicht existiert.
Nexus schrieb:
Du möchtest also ein Get/Set-Paar für gewisse Variablen automatisch erstellen? Ganz automatisch geht nicht.
Genau, im Prinzip möchte ich eine Klasse erstellen, die die Werte für eine Klasse (in meinem obigen Bsp. die CDisplay-Class) annimmt per Get()-Funktion, diese Werte überprüft (z.B. Max und Min Wert von dem Kontrast) und anschließend den private Member der CDisplay Class m_contrast setzt.
Nexus schrieb:
Normalerweise schreibt man Setter und Getter von Hand. Aber natürlich nur für diejenigen Attribute, die nach aussen überhaupt eine Eigenschaft der Klasse repräsentieren.
Die Property-Class soll neben der Kapselung z.B. auch eine Typkonvertierung leisten.
D.h. die class CDialog fordert z.B. den Kontrastwert der CDisplay class an, welcher als String abgespeichert wurde, benötigt diesen Wert aber als Int. die Property-Class soll daher z.B. auch in der Lage sein, diese Typkonvertierung durchzuführen.
Außerdem soll die CDialog class gar nicht wissen, wie und in welcher Form die privaten Member der CDisplay abgespeichert oder erzeugt werden.
Gruß
Jakob
-
Also ein mehr oder weniger klassicher Adapter. In deinem ersten Code gibst du allerdings die interne Klasse
CDisplay()mitGetObject()zurück, was ja nicht wirklich Sinn der Sache ist.Du meinst im Prinzip sowas, oder?
class Property { public: void SetContrast(int contrast) { assert(/* contrast ist gültiger Wert */); CString contrastStr = /* contrast in String umgewandelt */; myDisplay.SetContrast(constrastStr); } int GetContrast() const { CString contrastStr = myDisplay.GetContrast(); return /* contrastStr in int umgewandelt */; } private: Display myDisplay; };Und was willst du jetzt genau? Diese
Property-Klasse verallgemeinern, sodass sie mehrere Klassen oder zumindest mehrere Attribute einer Klasse wrappen kann? Falls ja, wäre es gut zu wissen, wie gross der Aufgabenbereich sein soll. Welche Fälle sollPropertyabdecken, worin unterscheiden sich die unterschiedlichen Attribute?P.S. "C" ist das Präfix für Klassen der MFC. Ich würde es nicht für eigene Klassen verwenden.
-
Nexus schrieb:
Also ein mehr oder weniger klassicher Adapter. In deinem ersten Code gibst du allerdings die interne Klasse
CDisplay()mitGetObject()zurück, was ja nicht wirklich Sinn der Sache ist.Schon mal danke für deine Hilfe. Das ist richtig, die Dialog class soll die Display class nicht kennen bzw. kennen müssen.
Ich hab insgesamt 5 Klassen, die ich gern mit so einer Property Class wrappen möchte: u.a .die Display Class, eine Network Class, eine SerialPort Class, eine XML Class.
Wenn wir bei der Displac Class bleiben: muss hier die Property Class in der Lage sein, den Kontrast, die Helligkeit setzen, verifizieren und zurückgeben können. Als dritter Parameter besitzt die Display Class noch den UINT Wert Status (ob das Display ein- oder ausgeschaltet ist). Der Kontrast- und der Helligkeitswert müssen von CString zu UINT gewandelt werden. Des Weiteren soll bei der Set-Methode überprüft werden können, ob der Kontrastwert sich z.B. zwischen 0 - 100 befindet und nicht etwa 102 eingegeben worden ist...
Wie gesagt für mich ist das Neuland

Dein Ansatz von der class Property sieht gut aus; allerdings weiß ich nicht ob man das noch etwas verallgemeinen kann, da man ansonsten für jeden Wert (z.B. Kontrast, Helligkeit etc.) eine Funktion für Set und eine Funktion für Get benötigt.Vielleicht existiert die Verify-Funktion für den Kontrastwert z.B. gar nicht in der Property-Class, sondern in der Display-Class, aber die Property-Class hat nur die Möglichkeit diese Funktion über die private Membervariable aufzurufen. Ich weiß leider nicht wie man das normalerweise löst
weil ich es noch nie gemacht habe.class Property { public: void SetContrast(int contrast) { assert(/* contrast ist gültiger Wert */); CString contrastStr = /* contrast in String umgewandelt */; myDisplay.SetContrast(constrastStr); } int GetContrast() const { CString contrastStr = myDisplay.GetContrast(); return /* contrastStr in int umgewandelt */; } private: Display myDisplay; Network myNetwork; SerialPort mySerial; XML myXml; };Nexus schrieb:
Und was willst du jetzt genau? Diese
Property-Klasse verallgemeinern, sodass sie mehrere Klassen oder zumindest mehrere Attribute einer Klasse wrappen kann? Falls ja, wäre es gut zu wissen, wie gross der Aufgabenbereich sein soll. Welche Fälle sollPropertyabdecken, worin unterscheiden sich die unterschiedlichen Attribute?Bin mir nicht ganz sicher was du mit Aufgabenbereich definierst. Insgesamt an Typen kommen UINT, CString, CStringList (ich weiß diese beiden sind aus der MFC, aber soll erstmal nicht weiter stören, da das eigentliche Problem ja ein C++-Problem ist), DWORD.
Bei meinem Ansatz dachte ich mir (erstes Posting), dass man mehrere Konstruktoren benötigt für die Property-Class mit Hilfe derer man festlegen kann welche Klasse überhaupt angesprochen werden soll (Display, Network Klasse etc.).
void Dialog::Init() { Property myProper; }Hier würde ja jetzt erst einmal der Standardkonstruktor von der Property-Class aufgerufen werden.
Gruß
Jakob
-
Jakob Hoffmann schrieb:
Dein Ansatz von der class Property sieht gut aus; allerdings weiß ich nicht ob man das noch etwas verallgemeinen kann, da man ansonsten für jeden Wert (z.B. Kontrast, Helligkeit etc.) eine Funktion für Set und eine Funktion für Get benötigt.
Die Verallgemeinerung ist momentan eben auch mein Problem.

Zuerst sollte man sich die Frage stellen, ob wirklich eine Klasse gleich mehrere interne Klassen (
Display,Network, ...) kapselt, oder jeweils nur eine. Wenn du nämlich ohnehin nur auf die Funktionalität einer gewrappten Klasse gleichzeitig zugreifst, kann man diese gleich aufteilen.Und damit eine Verallgemeinerung überhaupt möglich ist, muss genau bekannt sein, wie die einzelnen Klassen angesprochen werden. Könntest du ein paar Fälle, wie du die Adapterfunktionen manuell implementieren würdest, an Code aufzeigen? Sodass ich sehe, wo ähnliche Schnittstellen und Vorgehensweisen auftreten. Wenn sich diese nämlich stark unterscheiden, lohnt sich eine generische Lösung vielleicht gar nicht.
-
Nexus schrieb:
Jakob Hoffmann schrieb:
Dein Ansatz von der class Property sieht gut aus; allerdings weiß ich nicht ob man das noch etwas verallgemeinen kann, da man ansonsten für jeden Wert (z.B. Kontrast, Helligkeit etc.) eine Funktion für Set und eine Funktion für Get benötigt.
Die Verallgemeinerung ist momentan eben auch mein Problem.

Bin ich froh, dass ich nicht alleine bin

Ich mach mal ein Beispiel anhand der Display-Klasse, da diese die einfachste von allen ist. Ich habe eine Dialog-Klasse, die Editfelder, Checkboxen etc. darstellt. Diese Felder etc. müssen mit den entsprechenden Werten gefüllt werden - die in diesem Fall (Display-Dialog) aus der Display-Class kommen und Helligkeit, Kontrast und State (Display on /off) sind.
void Display::InitDialog() { Property displayprop; //editfield für den Kontrastwert füllen m_editFieldKontrast.SetWindowText(displayprop.GetValue()); //checkbox (display state on/off setzen) m_checkDispState.SetState(displayprop.GetValue()); //des weiteren (ganz vergessen, beinhaltet die Displayklasse auch //die verwendete CFont) m_checkDispState.SetFont(displayprop.GetValue()); }Habs jetzt mal ganz allgemein gehalten, nur um zu zeigen, was ich erreichen möchte mit dieser Property-Klasse. In der jeweiligen Dialogklasse sollen z.B. durch diese Propertyklasse keinerlei Umwandlungen / Typkonvertierungen mehr notwendig sein.
Wenn man sich jetzt z.B. den Netzwerk-Dialog anschaut, sieht es hier ähnlich aus, weil im Dialog selbst wieder Checkboxen, Editfelder etc. mit Daten aus der jeweiligen Klasse (hier der Netzwerk-Klasse) gefüllt werden sollen. Also auf der Seite des jeweiligen Dialogs ist auf jeden Fall eine große Übereinstimmung vorhanden.
Bezüglich der Verallgemeinerung - nur eine Idee, ob sie Sinn macht keine Ahnung:
class Property { enum { DisplayType = 1, NetworkType = 2, } PropertyType; //und dann im Konstruktor Property(UINT type = 0) { m_type = type; } private: UINT m_type; };Dann könnte man anhand des Types festlegen welche Funktionen aufgerufen werdne sollen oder nicht...
Nexus schrieb:
Zuerst sollte man sich die Frage stellen, ob wirklich eine Klasse gleich mehrere interne Klassen (
Display,Network, ...) kapselt, oder jeweils nur eine. Wenn du nämlich ohnehin nur auf die Funktionalität einer gewrappten Klasse gleichzeitig zugreifst, kann man diese gleich aufteilen.Dachte nur, normalerweise wird bei C++ ja alles im Normalfall gern allgemein gehalten, und abstrakt.
Nexus schrieb:
Und damit eine Verallgemeinerung überhaupt möglich ist, muss genau bekannt sein, wie die einzelnen Klassen angesprochen werden. Könntest du ein paar Fälle, wie du die Adapterfunktionen manuell implementieren würdest, an Code aufzeigen? Sodass ich sehe, wo ähnliche Schnittstellen und Vorgehensweisen auftreten. Wenn sich diese nämlich stark unterscheiden, lohnt sich eine generische Lösung vielleicht gar nicht.
-
Jakob Hoffmann schrieb:
kann mir jmd von euch helfen eine Property-Class zu erstellen, die als Wrapper für mehrere andere Klassen dienen soll und als Aufgabe hat die Get(), Set() Methoden zu integrieren bzw. auch gleichzeitig zu überprüfen ob die Werte bei der Set() Methode valid sind?
Ich frage mich, warum du diese Überprüfung nicht mit in die Klasse packst. Sonst kann man diese Überprüfung ja ganz einfach umgehen. Verstehe den Sinn da nicht.
Nexus schrieb:
Ich bin mir nicht sicher, ob ich deine Absicht genau verstanden habe. Properties gibts in C#, aber nicht in C++.
Wenn man sie will, lassen sie sich aber relativ einfach in C++ nachbauen. Mit dem gleichen syntaktic sugar für den Nutzer.
Nexus schrieb:
Du möchtest also ein Get/Set-Paar für gewisse Variablen automatisch erstellen? Ganz automatisch geht nicht. Du könntest Makros verwenden, aber das würde ich nicht tun. Die Schnittstelle wird dadurch verschleiert und allfällige Fehler sind sehr mühsam zu finden.
Ginge auch mit Funktoren. Da könnte man sich einige vordefinieren, so dass man nur noch die entsprechenden Werte setzen muss... Läuft aber auf recht viele Templates hinaus...
-
ProgChild schrieb:
Jakob Hoffmann schrieb:
kann mir jmd von euch helfen eine Property-Class zu erstellen, die als Wrapper für mehrere andere Klassen dienen soll und als Aufgabe hat die Get(), Set() Methoden zu integrieren bzw. auch gleichzeitig zu überprüfen ob die Werte bei der Set() Methode valid sind?
Ich frage mich, warum du diese Überprüfung nicht mit in die Klasse packst. Sonst kann man diese Überprüfung ja ganz einfach umgehen. Verstehe den Sinn da nicht.
Wenn lediglich die Property-Klasse einen privaten Member der Klassen (z.B. Display) besitzt, kann man diese Überprüfung auch nicht umgehen. Die Klasse selbst besitzt ja keine Member ansonsten.
-
Jakob Hoffmann schrieb:
Habs jetzt mal ganz allgemein gehalten, nur um zu zeigen, was ich erreichen möchte mit dieser Property-Klasse. In der jeweiligen Dialogklasse sollen z.B. durch diese Propertyklasse keinerlei Umwandlungen / Typkonvertierungen mehr notwendig sein.
Okay. Ich glaube, so langsam verstehe ich, was du meinst.
Du könntest zwar schon eine zentrale
Property-Klasse haben, dort Daten sammeln und diese vonDialogetc. abfragen lassen. Allerdings müsstest du verschiedene Typen speichern, von denen einige gar nicht gebraucht werden, und du würdest die Information über die Funktion der einzelnen Werte inPropertyverlieren. Ich weiss nicht, ob sowas eine gute Idee ist.Wäre nicht eine Factory-Funktion, die
Display-Objekte erzeugt, eine Möglichkeit?Display CreateDisplay(UINT contrast, UINT brightness, bool state) { assert(/* Kontrast gültig */); assert(/* Helligkeit gültig */); // ... Display d; d.SetContrast(ToString(contrast)); d.SetBrightness(ToString(brightness)); d.SetState(state); // ... return d; }Oder allenfalls eine nachträgliche Initialisierung (wobei ich die obere Möglichkeit vorziehen würde):
void InitDisplay(Display& d, UINT contrast, UINT brightness, bool state);So könnte die
Display-Klasse unberührt bleiben, und du müsstest die Attribute nicht erst in einer Property-Klasse sammeln (und hast auch deren Nachteile nicht). Ist dann zwar nicht mehr generisch, aber das wäreDisplay::InitDialog()ja auch nicht.Jakob Hoffmann schrieb:
Dachte nur, normalerweise wird bei C++ ja alles im Normalfall gern allgemein gehalten, und abstrakt.
Hat was.

-
Nexus schrieb:
Wäre nicht eine Factory-Funktion, die
Display-Objekte erzeugt, eine Möglichkeit?Was versteht man denn allgemein unter einer Factory-Funktion? In der Funktion sehe ich nur, dass eine Instanz von der Klasse Display erzeugt wird und mit den zu Beginn des Programms bekannten Werten (Kontrast etc.) initialisiert wird.
Als Returnwert bekomm ich z.B. einen Pointer auf dieses Objekt. Wenn ich jetzt den Kontrast während des Programms geändert haben möchte bzw. der User, dann funktioniert das nur über diesen Pointer, oder? Und ich rufe die Get und Set Funktionen direkt von der Display-Klasse auf?
Jetzt versteh ich bloß noch nicht wie ich die Werte ändern kann, ohne direkt auf die Klasse Display zugreifen zu müssen?
Nexus schrieb:
So könnte die
Display-Klasse unberührt bleiben, und du müsstest die Attribute nicht erst in einer Property-Klasse sammeln (und hast auch deren Nachteile nicht). Ist dann zwar nicht mehr generisch, aber das wäreDisplay::InitDialog()ja auch nicht.Display::InitDialog() erzeugt ein Dialogfenster, welches z.B. Instanzen hat wie Checkboxen und Editfelder, die mit den entsprechenden Werten ausgestattet werden müssen (aus der Display-Klasse z.B.). Jedesmal wenn dieser Dialog erzeugt wird; wird dieser Dialog released, dann müssen die getätigten Veränderungen in diesen Instanzen (Editboxen) etc. wieder an die jeweilige Klasse (Display-Klasse in diesem Fall) übertragen werden per SetParams() oder Property-Klass.
-
Jakob Hoffmann schrieb:
Was versteht man denn allgemein unter einer Factory-Funktion?
Eine externe Funktion (nicht Konstruktor), die für die Erzeugung eines Objekts sorgt.
Jakob Hoffmann schrieb:
Jetzt versteh ich bloß noch nicht wie ich die Werte ändern kann, ohne direkt auf die Klasse Display zugreifen zu müssen?
Ich dachte, die Änderungen geschähen primär bei der Initialisierung. Sonst hast du Recht, dann würde sich der Ansatz nicht bewähren.
Hm... Naja, dann nimmst du vielleicht doch eine zentrale Datensammlung in
Property. Vielleicht sowas, wobei duenums zur Fallunterscheidung je nach Aufgabenbereich benutzen kannst.class Property { public: SetUint(int id, UINT value); UINT GetUint(int id) const; SetBool(int id, bool value); bool GetBool(int id) const; private: std::map<int, UINT> myUintMap; std::map<int, bool> myBoolMap; }; // Anwendung: namespace DialogAttribute { enum Type { Contrast, Brightness, State, }; } int main() { Property p; p.SetUint(DialogAttribute::Contrast, 45); p.SetUint(DialogAttribute::Brightness, 80); p.SetBool(DialogAttribute::State, true); }Obwohl das nicht wahnsinnig sauber ist. Du musst vor allem schauen, dass die IDs nie kollidieren. Aber z.B. OpenGL macht das auch so, obwohl es natürlich C ist... Ich habe dennoch das Gefühl, einzelne Wrapperklassen wären einfacher. Nicht immer musst du den abstrakten Weg wählen.
