Shor-ty
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
Hallo zusammen, ich möchte von mehreren Objekten einer Klasse auf ein Objekt einer anderen Klasse zugreifen. Eine Vererbung möcht ich nicht machen, da es folgendermaßen aufgebaut ist: Klasse Chemistry enthält chemisch, thermodynamische und transport Funktionen, sowie Elementarreaktionen und deren Berechnungsmethoden. Diese wird am Anfang erstellt und ändert sich nicht mehr. Klasse MixtureFraction enthält bspw. die Zusammensetzung von einem Gas und soll die Berechnungsmethoden vom Objekt Chemistry erhalten.
Wieso ich keine Vererbung machen möchte (und ich hoffe ihr stimmt mir zu) ist folgender Grund:
In der Klasse MixtureFraction werden Daten für die Berechnung gespeichert (bspw. Zusammensetzung von Gasgemischen etc.). Das geschieht jedoch nur an diskreten Punkten. Dementsprechend habe ich für jeden Punkt ein Objekt der Klasse MixtureFraction (möglicherweise 1000 Objekte). Wenn ich über eine Vererbung gehe, dann hab ich in den 1000 Objekten auch 1000x das chemische Objekt, welches dann 1000x identisch ist und somit eigentlich Speicherplatz besetzt, oder. Deswegen dachte ich das jedes Objekt von MixtureFraction einen Pointer auf das Objekt der Klasse Chemistry erhält und damit die Funktionalitäten aufgerufen werden können. Ist das ein guter Ansatz? Wenn ja, wie würdet ihr vorgehen? Mein derzeitiger Gedanke ist, eine Funktion in MixtureFraction zu implementieren, die das Chemistry Objekt übernimmt und dann einen Pointer auf dieses zurückgibt. Hoffe das es einizgermaßen plausibel formuliert wurde.
Grüße Tobi PS: Ggf. wäre es sinnvoll die Adresse des Objekts der Chemistry Klasse über den Konstruktor der MixtureFraction Klasse zu übergeben.
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Und von welcher Sprache reden wir? C++, Java, Scala, Smalltalk, ...? Wg. des Wortes "Pointer" tippe ich mal auf C++. Ohne viel von Chemie und Deinem Problem verstanden zu haben kann man das aber partiell ohne Kenntnis der Sprache diskutieren. Wenn eine Klasse Berechnungsmethoden oder ~funktionen enthält und keinen Status speichert, keine Variablen enthält, dann eignet sie sich als statische Klasse wie etwa in Java die Klasse java.lang.Math, die nur statische Methoden enthält. Evtl. lässt sich erst durch Redesign eine solche Klasse isolieren. Deren Methoden müssen dann nur 1x im Speicher liegen. Ohne mich mit Binärformat u.ä. beschäftigt zu haben würde ich aber sagen, dass andere Methoden auch nur 1x im Speicher sein müssen (außer der Code läuft nebenläufig mehrfach gleichzeitig). Des sauberen Designs wegen ist eine solche Aufteilung dennoch wünschenswert.
|
Shor-ty
(Themenstarter)
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
Hallo, oh vollkommen vergessen aber wie du richtig gesagt hast geht es um C++.
Letzten Endes ist es ja (wie du bereits sagtest) egal, in welchem Themengebiet sich das Programm bewegt. Die Klasse Chemistry öffnet vier Dateien, liest alle Daten ein und wird dann nicht mehr verändert. Sie liefert also die Berechnungsmethoden für die andere Klasse. Die allgemeine Frage hast du mir bereits beantwortet: Des sauberen Designs wegen ist eine solche Aufteilung dennoch wünschenswert.
Entsprechend gehe ich davon aus, dass mein Weg mit einem Pointer gar nicht so schlecht ist, oder? Der Code, soll ggf. später parallelisiert werden (aber das ist vorab überhaupt nicht von Interesse). Es kann aber sein das Funktionen mehrfach aufgeruft werden (weiß aber nicht ob das ein durcheinander ergeben kann):
| resultat = berechnung(a) * berechnung(b) * berechnung(c);
|
Danke schonmal für die Antwort.
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Shor-ty schrieb: Hallo, oh vollkommen vergessen aber wie du richtig gesagt hast geht es um C++.
Letzten Endes ist es ja (wie du bereits sagtest) egal, in welchem Themengebiet sich das Programm bewegt. Die Klasse Chemistry öffnet vier Dateien, liest alle Daten ein und wird dann nicht mehr verändert.
Ein Objekt dieser Klasse tut das, um penibel zu sein.
Des sauberen Designs wegen ist eine solche Aufteilung dennoch wünschenswert.
Entsprechend gehe ich davon aus, dass mein Weg mit einem Pointer gar nicht so schlecht ist, oder?
Deswegen dachte ich das jedes Objekt von MixtureFraction einen Pointer auf das Objekt der Klasse Chemistry erhält und damit die Funktionalitäten aufgerufen werden können.
Ich finde den sprachlichen Ausdruck ungewohnt. "Pointer" ist m.E. eine low-level-Beschreibung der Umsetzung, wo Du Dich sonst auf einem abstrakteren Niveau bewegst, und von Vererbung redest, wo der Gegensatz Delegation wäre, also dass die Klasse ein Chemistry (?) ist oder einen Chemistry hat. Beim Haben unterscheidet man dann wieder statische und private oder const-Member usw.. Ob das nun eine Referenz ist oder ein Pointer macht m.W. wenig Unterschied.
Der Code, soll ggf. später parallelisiert werden (aber das ist vorab überhaupt nicht von Interesse). Es kann aber sein das Funktionen mehrfach aufgeruft werden (weiß aber nicht ob das ein durcheinander ergeben kann):
Kann es nicht. Angenommen eine Demoklasse XWithAdder, die eine Add-Methode für positive Zahlen enthält. | int add (int a, int b) {
if (b == 0) return a;
return add (a+1, b-1);
}
|
Die Methode manipuliert nur zwei Parameter, keine Attribute der Klasse. Wenn Du 1000 Objekte der Klasse hast - die Methode ist immer die gleiche. Auch kannst Du die Methode für das umschließende Objekt beliebig oft aufrufen. Beim Aufruf selbst wird sie auf den Stack kopiert und nach Ablauf wieder abgeräumt. Durcheinander kann da nichts kommen. Nur wenn die Methode Seiteneffekte hat, dann kann es, für das Objekt, zu Verwirrungen kommen. Zurück zur Frage: Wenn das Objekt vom Typ Chemistry vorher erstellt werden kann, dann könnte dem Konstruktor der MixtureFraction-Objekte die Referenz (o.d.P.) darauf übergeben werden - dieses Objekt wäre dann garantiert initialisiert und müsste nicht auf Existenz geprüft werden. Es kann aber Gründe geben das anders zu lösen.
|
Shor-ty
(Themenstarter)
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
user unknown schrieb:
Deswegen dachte ich das jedes Objekt von MixtureFraction einen Pointer auf das Objekt der Klasse Chemistry erhält und damit die Funktionalitäten aufgerufen werden können.
Ich finde den sprachlichen Ausdruck ungewohnt. "Pointer" ist m.E. eine low-level-Beschreibung der Umsetzung, wo Du Dich sonst auf einem abstrakteren Niveau bewegst, und von Vererbung redest, wo der Gegensatz Delegation wäre, also dass die Klasse ein Chemistry (?) ist oder einen Chemistry hat. Beim Haben unterscheidet man dann wieder statische und private oder const-Member usw.. Ob das nun eine Referenz ist oder ein Pointer macht m.W. wenig Unterschied.
Ich bin nicht so bewandert mit der korrekten Ausdurcksweise, also bitte verzeih mir. Kann damit gerade nicht so viel anfangen.
Angenommen eine Demoklasse XWithAdder, die eine Add-Methode für positive Zahlen enthält. | int add (int a, int b) {
if (b == 0) return a;
return add (a+1, b-1);
}
|
Die Methode manipuliert nur zwei Parameter, keine Attribute der Klasse. Wenn Du 1000 Objekte der Klasse hast - die Methode ist immer die gleiche. Auch kannst Du die Methode für das umschließende Objekt beliebig oft aufrufen. Beim Aufruf selbst wird sie auf den Stack kopiert und nach Ablauf wieder abgeräumt. Durcheinander kann da nichts kommen. Nur wenn die Methode Seiteneffekte hat, dann kann es, für das Objekt, zu Verwirrungen kommen.
Was meinst du mit Seiteneffekte?
Zurück zur Frage: Wenn das Objekt vom Typ Chemistry vorher erstellt werden kann, dann könnte dem Konstruktor der MixtureFraction-Objekte die Referenz (o.d.P.) darauf übergeben werden - dieses Objekt wäre dann garantiert initialisiert und müsste nicht auf Existenz geprüft werden. Es kann aber Gründe geben das anders zu lösen.
Das Objekt vom Typ Chemistry wird als erstes erstellt. An die Referenz hatte ich noch gar nicht gedacht. Dann wäre eine Übergabe als konstante Referenz ggf. auch eine gute Idee.
Ich dachte mir, dass ich die Chemistry Objekt Adresse in einem Pointer der MixtureFraction Klasse speicher und dadurch, durch Dereferenzierung des Pointers, auf die Klassenfunktionen vom Chemistry Objekt zugreifen kann. Wobei es in meinem Fall wahrscheinlich egal ist, ob ich eine Referenz übergebe oder einen Pointer. Danke für deine Rückantwort.
|
Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Es kann aber sein das Funktionen mehrfach aufgeruft werden (weiß aber nicht ob das ein durcheinander ergeben kann):
Das passiert nur, wenn die Funktion auf statische oder globale Daten zugreift und diese verändert.
|
Shor-ty
(Themenstarter)
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
Dakuan schrieb: Es kann aber sein das Funktionen mehrfach aufgeruft werden (weiß aber nicht ob das ein durcheinander ergeben kann):
Das passiert nur, wenn die Funktion auf statische oder globale Daten zugreift und diese verändert.
Die Funktionen erhalten lediglich Werte aus den Objekten der Klasse MixtureFraction. Diese werden für die Berechnung verwendet und dann entsprechende Werte in den Objekten angepasst.
Globale oder statische Daten werden nicht verändert.
|
Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Ich wollte nur auf diese Feinheit hinweisen, weil user unknown generell ausgeschlossen hatte, das es zu Problemen kommen könnte. Als ich noch nur in C programmiert hatte, hatte ich einige Funktionen, die Zeiger auf lokale statische Strings zürücklieferten. So etwas ist nicht reentrant und nicht threadsave. Letzteres ist modernen GUIs aber immer erforderlich. Das war also nur ein Sicherheitshinweis.
|
Shor-ty
(Themenstarter)
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
Hallo Dakuan, sollte auch nicht so rüber kommen, dass dein Hinweis nicht relevant ist. Wollte nur nochmals aufzeigen, wie's derzeit ist. Ob ich irgendwo noch globale oder statische Werte definieren werde ist offen und wenn es so sein sollte, dann hab ich jetzt jedenfalls schon mal etwas im Hinterkopf. Danke dafür. Bezüglich C++ sind meine Erfahrungen in so einem großen Projekt eher flau und deswegen frage ich hier lieber nach, um Meinungen anzuhören Hätte ja auch sein können, dass mein Vorhaben mit den zwei Klassen komplett daneben ist und das keine gute (im Sinne von C++ Struktur/Aufbau) Programmierung ist und ggf. starke Zeiteinbusen bei der Berechnung mit sich bringt (die Berechnungen sind sehr intensiv). Ich werde die Tage jedenfalls mal eine Referenz im Konstruktor auf das bereits exisitierende Objekt der Klasse Chemistry implementieren. Sollte damit dann auf die Berechnungsmethoden zugreifen können. Die Frage war ja mit unter, ob dies empfehlenswert ist oder nicht (: In dem Sinne danke für eure - bisherigen - Antworten und wünsche euch eine gute Nacht.
Grüße Tobi
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Shor-ty schrieb:
Ich bin nicht so bewandert mit der korrekten Ausdurcksweise, also bitte verzeih mir. Kann damit gerade nicht so viel anfangen.
Die korrekte Ausdrucksweise zu lernen ist nötig wenn Du mit anderen über das Programmieren reden willst, und darüber zu reden ist nötig um zu lernen. Es kann Dir also nicht verziehen werden, wenn Du es nicht lernst. Umgekehrt muss ja jeder mal damit anfangen, und daher brauchst Du nicht um Verzeihung zu bitten, dass Du nicht mit der magischen Fähigkeit geboren wurdest. Achte also auf die Ausdrucksweise beim Hören und Lesen und sei gewarnt - viele Programmierer sind lausig, oberflächlich, undpräzise und quasi funktionale Analphabeten wenn sie über Programme sprechen - manchmal können sie dennoch beachtlich gut programmmieren.
|
Shor-ty
(Themenstarter)
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
user unknown schrieb: Shor-ty schrieb:
Ich bin nicht so bewandert mit der korrekten Ausdurcksweise, also bitte verzeih mir. Kann damit gerade nicht so viel anfangen.
Die korrekte Ausdrucksweise zu lernen ist nötig wenn Du mit anderen über das Programmieren reden willst, und darüber zu reden ist nötig um zu lernen. Es kann Dir also nicht verziehen werden, wenn Du es nicht lernst. Umgekehrt muss ja jeder mal damit anfangen, und daher brauchst Du nicht um Verzeihung zu bitten, dass Du nicht mit der magischen Fähigkeit geboren wurdest. Achte also auf die Ausdrucksweise beim Hören und Lesen und sei gewarnt - viele Programmierer sind lausig, oberflächlich, undpräzise und quasi funktionale Analphabeten wenn sie über Programme sprechen - manchmal können sie dennoch beachtlich gut programmmieren.
Danke für die Rückmeldung und Ergänzung.
Nach kurzer Recherche kann ich bestätigen, dass ich die Delegation der Klasse Chemistry zur Klasse MixtureFraction benötige ☺
Ich werde die Implementierung über den Konstruktor der Klasse MixtureFraction und die Delegation über eine konstante Referenz tätigen. Da ich das Objekt nicht ändere, wäre wohl eine Referenz besser als ein Pointer. Danke für eure ganzen Antworten. Hat mir jedenfalls einiges gebracht.
|
Dee
Anmeldungsdatum: 9. Februar 2006
Beiträge: 20087
Wohnort: Schwabenländle
|
Vielleicht noch eine Anmerkung von mir: Es ist auch leichter über sein Design zu sprechen, wenn jede Klasse eine eindeutige Verantwortlichkeit hat und auch entsprechend benamt wird. Dies nennt sich Single-Responsibility-Prinzip. (Ich finde die Übersetzung mit „eine“ unglücklich, da die oft dazu verleitet, das Prinzip über zu interpretieren.) Jedenfalls hätte ich von einer Klasse namens Chemistry nie erwartet, dass sie Dateien einliest. Dafür ist der Name zu generisch. Ich weiß ja nicht, was in den Dateien steht, aber ein ChemistryReader (oder so etwas in der Art), der die Daten einliest und dann in Chemistry steckt (oder Chemistry ruft den ChemistryReader) wäre der nach SRP bessere Ansatz. Ich würde vermutlich sogar Deine Chemistry aufteilen in ChemistryData und ChemistryCalculation, was Daten und Methoden kapselt. Aber so genau habe ich den Zusammenhang auch nicht verstanden. Ein zweiter Tipp: Lies Dich ein bisschen in Klassendesign und -darstellung ein. Das muss kein UML sein, aber ein Bild mit den relevanten Klassen und Beziehungen (Interface-Realisierung, Generalisierung, Assoziation, Aggregation, Abhängigkeit etc.) hilft beim Austausch einer Idee sehr oft. Wenn Du die Basismechanismen von UML nutzt (ich nenne das Simplified-UML) entstehen meist auch keine oder nur wenig Verwirrungen über die genaue Interpretation des gezeigten. Ich hoffe, das hilft ein bisschen. Gruß Dee
|
Shor-ty
(Themenstarter)
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
Hallo Dee, danke für deine Antwort und für die Hinweise. Ich sehe schon, dass man auf die Wortwahl deutlich achten sollte, wenn es um Diskussionen in diesem Bereich geht.
Ich stimme dir zu, dass es besser wäre die Klasse Chemistry zu splitten und Daten, Methoden und den Reader zu trennen. Ich lerne jedenfalls schon jede Menge in meinem Projekt und die Datenstruktur ist bestimmt optimierbar. Allerdings lernt man C++ erst gut wenn man selber etwas größeres programmiert und da bin ich gerade dabei (und es macht rießig Spaß, auch wenn ihr sicherlich einiges ändern würdet). Jede Kritik hilft jedenfalls mein Tun zu verbessern und auch mein Wissen über das ganze Thema zu verbessern.
Danke an alle. Grüße Tobi
|
Shor-ty
(Themenstarter)
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
Anbei noch eine kurze Frage zwecks Ordnerstruktur. Wenn ich die Klasse Chemistry in ChemistryReader, ChemistryData und ChemistryCalculation aufteile, werden dann alle Header und Source Dateien in einen Ordner "Chemistry" gepackt oder wird für jede Klasse ein eigener Ordner mit Header und Source erstellt? Soweit ich mich entsinnen kann, werden zusammengehörige Klassen/Source-/Headerdateien in den gleichen Ordner gespeichert.
|
Shor-ty
(Themenstarter)
Anmeldungsdatum: 10. September 2010
Beiträge: 719
Wohnort: Bad Wörishofen
|
Anbei mal eine sehr grobe Übersicht bezüglich meinem Projekt.
Da kann man sicherlich noch einiges verbessern.
- Aufbau.pdf (40.7 KiB)
- Download Aufbau.pdf
|