Globale Parameter - Wie am besten realisieren ?
-
Hallo,
ich habe mich gerade angemeldet und dies ist mein 1. Post.
Ich schreibe gerade mein erstes großes Programm in C++ und QT.
Bisher habe ich nur in Assembler und C programmiert, hauptsächlich
auf Mikrocontrollern.Ich bin also C++ Anfänger.
In diesem Programm benötige ich relativ viele Parameter, die allen
Klassen zur Verfügung stehen müssen.
Dies habe ich bisher so gelöst, daß ich eine Klasse geschrieben habe,
die diese Parameter aus einer Datei einließt und in eine globale
statische Variable schreibtz.B.
in der .h Datei
class Parameter { public: static unsigned int Parameter 1,Parameter2; u.s.w. }am Anfang der .c datei
unsigned int Parameter::Parameter1; unsigned int Parameter::Parameter1; u.s.wIn den entsprechenden Klassen kann ich dann diesen globalen Variablen
Werte zuweisen oder diese auslesen.
Dies funktioniert bisher sehr gut.Ich hatte auch mal mit Singleton experementiert, dies aber nie zum laufen bekommen.
Das Problem ist jetzt,daß ich ungefähr 30 Parameter 6 mal benötige.
Dies ist eine unübersichtlich hohe Zahl, daher möchte ich gerne die Variablen
in eine Struktur packen und dann halt 6 mal definieren.
Dann könnte ich auch über Zeiger auf die Struktur zugreifen und damit
könnte ich mir viel Code ersparen.z.B. so
struct { Variable 1 Variable 2 u.s.w. }Parametersat1, Parametersat2,..,Parametersatz6;Diese benötige ich natürlich global in allen Klassen.
Jetzt meine Frage:
Wie mache ich das ?
Ich habe mir eine Struktur erstellt, aber ich weiß nicht,
wie ich diese am Anfang der .c Datei richtig definiere.
Geht das überhaupt ?Kann ich es aber auch anders lösen ?
ich habe mal gelesen, daß man das über Pointer machen kann, die man einer
Klasse übergibt, um überhaupt globale Variablen zu vermeiden.
Ist das machbar und hat jemand mal ein Stück Code für mich ?Und ja, ich habe schon das Internet durchsucht und meine C++ Bücher
gewälzt, aber auf diese Thema keine Antwort gefunden;
außer mit Singleton oder static zu arbeiten.Danke an Alle
Michael J
-
Michael J schrieb:
In diesem Programm benötige ich relativ viele Parameter, die allen
Klassen zur Verfügung stehen müssen.Da ist dein Problem. Die Klassen sollten unabhängig sein. Wenn du globale Variablen brauchst dann geht es nicht besser als mit globalen Variablen (in einem namespace), ich bin mir jedoch sicher dass du keine brauchst und dann geht das Problem automatisch weg. Wenn du erklärst welche Parameter das sind und wieso alle Klassen die benutzen sollen finden wir sicher raus wie es besser geht.
-
Hallo,
ich antworte mal selber.
Ich habe mal eine Struktur global angelegt.
z.B.
parameter.h#include <irgendwas> struct Parameters { bool Test1; };parameter.c
#include "parameter.h" Parameters TestA;auswertung.c
#include "parameter.h" extern Parameters TestA; void auswertung::anfang (void) { TestA.Test1 = TRUE; }Wäre das so richtig ?
Ich nutze damit natürlich globale Variablen/Strukturen.
Eine andere Möglichkeit fällt mir nicht ein.
Außerdem nutze ich das Signal/Slot System von QT.
Ich weiß nicht, wie ich sonst die Parameter mit in einen Slot reinbekomme.Michael J
-
nwp3 schrieb:
Michael J schrieb:
In diesem Programm benötige ich relativ viele Parameter, die allen
Klassen zur Verfügung stehen müssen.Da ist dein Problem. Die Klassen sollten unabhängig sein. Wenn du globale Variablen brauchst dann geht es nicht besser als mit globalen Variablen (in einem namespace), ich bin mir jedoch sicher dass du keine brauchst und dann geht das Problem automatisch weg. Wenn du erklärst welche Parameter das sind und wieso alle Klassen die benutzen sollen finden wir sicher raus wie es besser geht.
Hallo,
das Programm soll über USB elektronische Baugruppen ansteuern.
Diese hängen an einem RS485 Bus und es können bis zu 6 Geräte sein.
Diese Geräte sind eigentlich alle gleich, haben nur unterschiedliche
Busadressen.
Diese Geräte haben alle die gleichen parametrierbaren Parameter,diese
Parameter können aber unterschiedlich sein.Dies Parameter sind für verschiedene Programmteile wichtig, die in mehreren
Klassen auf entsprechende .h und .c Dateien verteilt sind.
Z.B. Automatikbetrieb, Handbetrieb, u.s.w.
Parameter sind z.B. max. Geschwindigkeit, Verfahrweg, aktuelle Position u.s.w.
Als Oberfläche nutze ich QT mit dem Signal/Slot System.
Wenn jetzt durch Anklicken eines Button ein Slot ausgelöst wird, muß ich
halt unter Beachtung von diversen Parametern ein Telegramm per USB versenden.Soweit klar ?
Darum möchte ich auch eine Struktur nutzen.
Dann muß ich nämlich eine Funktion nur einmal schreiben , und je nachdem,
welches Gerät angewählt ist, per Zeiger aus der Struktur die Daten holen u.s.w.Michael J
-
struct Coord{ unsigned int x; unsigned int y; }; class ElektronischeBaugruppe{ public: char *adresse; unsigned int geschwindigkeit; unsigned int maximaleGeschwindigkeit; struct Verfahrweg verfahrweg; //??? void setHandbetrieb(); void setAutomatikbetrieb(); private: Coord position; /* position ist private, weil sie immer auf Basis der Zeit, Geschwindigkeit und alter Position neu berechnet werden muss */ public: Coord getPosition() const{ return position = position + geschwindigkeit * vergangeneZeit; } //QTSlot: kein plan, habe das Signal/Slot-Verfahren von QT nie richtig verstanden static void buttonAusloeserCallback(void *p){ ElektronischeBaugruppe &eb = *(ElektronischeBaugruppe *)p; SendeUsbSignal(eb.adresse, eb.getPosition(), eb.geschwindigkeit); } ElektronischeBaugruppe(char *adres, unsigned int maxGesch, Coord pos) : adresse(adres), geschwindigkeit(0), maximaleGeschwindigkeit(maxGesch), position(pos), verfahrweg(???){ } /* sonstige Funktionen, zum Beispiel adresse ändern wenn mans braucht, in einer Variablen merken, ob man Handbetrieb oder Automatik hat usw. */ };Du listest einfach auf was eine Elektronische Baugruppe ist, hat und kann. Das wäre schon mal ein Anfang ohne globale Variablen. Ich habe bestimmt die Hälfte missverstanden, aber das Prinzip sollte klar sein.
-
Hallo nwp3,
Danke für die Antwort.
Nur dann müßte ich doch alles in eine Klasse packen, oder ?
Das wird kaum praktikabel sein.
Die Klasse würde riesengroß und sehr komplex.ich müßte das über mehrere Klassen machen und dann wäre ich doch wieder
bei Singleton.Es gibt haufenweise Diskussionen im Netz über die Vor-/Nachteile von
Singleton, static und globale Variablen zu dem Thema.
Einen Königsweg scheint es nicht zu geben.Noch eine kurze Frage.
Was hat dieser Code für eine Funktion ?ElektronischeBaugruppe &eb = *(ElektronischeBaugruppe *)p;mfg
Michael J
-
eb ist eine Referenz, ein anderer Name für ein ElektronischeBaugruppe-Objekt. Man muss ihm sagen für welches Objekt es ein anderer Name sein soll, und da habe ich im das Objekt gegeben auf das p zeigt (umgecastet wegen void *).
int i; int &ir = i; //ir ist ein anderer Name für i, ist aber sinnlos, da kann man gleich i nehmen int main(){ int bla; foo(bla); } void foo(int &i){ //i ist ein anderer name für bla, was sinnvoll ist, denn auf bla kann man in foo nicht zugreifen i++; }Von Singletons halte ich nichts. Sie erfüllen praktisch keine Funktion (nur eine Instanz?), zerstören den Sinn von Klassen und Objekten und funktionieren häufig nichtmal, weil irgendwelche static Variablen in falscher Reihenfolge initialisiert werden und man das auch nicht fixen kann.
Alles in eine Klasse packen bringt natürlich nichts, dann lieber die Klasse weglassen und alles global machen. Ich sehe bei deinem Projekt zu wenig durch um die einzelnen Teile identifizieren zu können. Aber wenn man das könnte kann man für diese jeweils eigene Klassen bauen. Außerdem erscheint mir die ElektronischeBaugruppe gar nicht so kompliziert, aber das liegt wohl nur daran, dass du das nur sehr allgemein umrissen hast. Vielleicht ein Diagramm malen was woraus besteht und worauf zugreift, dann sieht man das schnell. Idealerweise sollte jedes Einzelteil trivial sein und dass alles von allem wissen muss erscheint unrealistisch.
-
Kannst du ein paar mehr Infos zu den Parametern und der Art der Initialisierung, Parameterdefinition, Workflow usw. geben?
Sollen zu Beginn bestimmte Parameter in die Baugruppen eingespielt werden? Liefern die Baugruppen im Betrieb laufend Parameter? WIE kommen die Parameter, d.h. haben sie eine spezielle Kennung oder eine Position im Datenpaket?Rein gefühlt würde ich auch eine Klasse machen, die EIN Gerät beschreibt. Und davon 6 Instanzen.
Sind die Parameter eines Geräts (d.h. dann in einer Klasse) so einzigartig, dass man für jeden eine bestimmte fixe Variable (d.h.: konkreten Namen) anlegen muss? Oder reicht es, Key-Value-Paare vorzuhalten, so dass die Klasse an sich nur ein Datencontainer ist und man Parameter etwa so setzt oder liest:enum par_e { SPEED, POSX, POSY, TEMP }; ... class Device .... Device device1; device1.setPar( SPEED, 35 ); int temp = device1.getPar( TEMP );Oder noch flexibler: Die Parameter über Namen ansprechen (Strings), wenn z.B. zu Beginn irgendwelche Settings aus einer Konfigurationsdatei eingelesen werden sollen:
device1.setPar( "SPEED", 35 ); int temp = device1.getPar( "TEMP" );
-
Hallo,
Kannst du ein paar mehr Infos zu den Parametern und der Art der Initialisierung, Parameterdefinition, Workflow usw. geben?
Sollen zu Beginn bestimmte Parameter in die Baugruppen eingespielt werden? Liefern die Baugruppen im Betrieb laufend Parameter? WIE kommen die Parameter, d.h. haben sie eine spezielle Kennung oder eine Position im Datenpaket?Das wäre sehr aufwendig.
Daher die Kurzform.Die Parameter werden zu Anfang aus einer Datei gelesen.
Die Parameter werden auch alle auf den Karten selber abgespeichert, da diese
auch dort benötigt werden.
Die Parameter können über eine extra Klasse mit einem QWidget geändert, aus der
Karte geladen, in die Karte gespeichert u.s.w. werden.
Bis jetzt sind dies etwa 30 Parameter pro Karte, es können noch mehr werden.
Die Parameter sind aber in jeder Karte verfügbar.
(Auf den Karten ist jeweils ein ATMEGA Mikrocontroller, dessen Firmware mit
dem PC Programm mitwächst; in C programmiert)Die Kommunikation erfolgt mit einem USB/RS485 Wandler auf einen seriellen Bus,
an den alle Karten angeschlossen sind.
Das Protokoll ist von mir.
Es enthält halt was man so braucht:
Präämbel,Quelle,Ziel,ID,Datenlänge,Daten,CRC16Die Kommunikation läuft über im Moment 2 "Kommunikationsmöglichkeiten"
1. zyklische Abfrage aller Karten -> zur Abfrage von Störungen, Positionen,
Temperaturwerten etc. (läuft automatisch im Hintergrund)2. angeforderte Kommunikation -> ich drücke einen Button, ein Telegramm
wird erstellt, und der entsprechende Befehl wird an die Karte gesendet und
die Rückantwort verarbeitet.Als Klasse habe ich z.B.
RS232 Kommunikation, Hauptfenster, mehrere
Konfigurationsfenster,Handbedienfenster u.s.wAlle Klassen brauchen halt bestimmte Parameter, um ihre Aufgaben
erfüllen zu können.
Den Slots kann (darf) ich nur maximal alle Parameter des Signals übergeben,
mehr geht nicht.Daher weiß ich nicht, wie ich dort einen möglichen Zeiger auf
die Parameterdaten rüberbekomme.Daher im Moment als Static.
Nur in einer Struktur wäre es mir lieber, da ich 6 x die gleichen Parameter
benötige und ein Zugriff per Zeiger ( um Code und Schreibarbeit zu sparen)
mir lieber wäre.Wie gesagt, ich bin immer noch Anfänger.
Die ist mein erstes QT und damit C++ Projekt.
Und alles steht auch nicht in den Büchern, ich habe schon ein paar.Diese Thema ist so eins, neben Programmstruktur,optimale Kommunikation
zwischen verschiedenen Klassen.mfg
Michael J
-
minastaros schrieb:
Rein gefühlt würde ich auch eine Klasse machen, die EIN Gerät beschreibt. Und davon 6 Instanzen.
Hoppla,
nichts dazu geschrieben.
Das hatte ich erst vor, bloß ich bräuchte Zugriff auf diese Klasse in allen
andern Klassen.
Dabei hat jede größere Klasse seine eigene .h und .cpp Datei.
Über genau diesen Punkte bin ich gestolpert.
Entweder geht sowas nicht, oder mir fehlt das Wissen
sowas QT kompatibel zu realisieren.mfg
Michael J
-
Mich interessiert genau der Punkt:
Michael J schrieb:
Präämbel,Quelle,Ziel,ID,Datenlänge,Daten,CRC16
Welche Form haben denn die Daten? Eher so:
"12,33,3453,344,2,0,0,234"oder sowas:
"PR=12;NA=33;SI=3453;TM=344;"
Die zweite Form macht es flexibler, wenn man später neue Parameter hinzufügt oder obsolete entfernt. Ab..er egal:Erstmal solltest du ein Design überlegen. Die angesprochene Klasse wäre zunächst nur ein Datencontainer, den man zwischen den Teilen des Systems austauschen kann. Damit man keine 30 Pointer hat sondern EIN Objekt, jeweils. Diese 6 Objekte liegen praktischerweise wiederum in einem Container (z.B. vector), der an zentraler Stelle im System vorgehalten wird. Diese zentrale Steuereinheit sorgt sich nun um den ganzen Workflow und übergibt (z.B. per Referenz) entweder den gesamten Container oder die einzelnen Objekte an das jeweilige Subsystem, das dann seine Teilaufgabe ausführt:
1. Etwas, was Konfigurationsparameter aus einer Datei liest und die entsprechenden Datencontainer damit füllt.
2. Etwas, was den Inhalt eines Datencontainers an ein Gerät schickt (seriell).
3. Etwas, was die Geräte ausliest und die Daten in ein Datencontainer schreibt.
4. Etwas, was die Daten eines Containers in der GUI anzeigt.
5. Etwas, was auf GUI-Events reagiert und die geänderten Werte in den Datencontainer zurückschreibt, dann Punkt 2 aufruft - oder für den nächsten zyklischen Schreib-/Lesevorgang bereitstellt.Dadurch, dass immer nur die Datencontainer, die benötigt werden, an das entsprechende Subsystem übergeben werden, braucht es keine globalen Variablen.
-
minastaros schrieb:
Mich interessiert genau der Punkt:
Michael J schrieb:
Präämbel,Quelle,Ziel,ID,Datenlänge,Daten,CRC16
Welche Form haben denn die Daten? Eher so:
"12,33,3453,344,2,0,0,234"Hallo,
Danke für Deine späte Antwort.
Die Daten haben das zitierte Format.
Die andere wäre auch problemlos möglich, aber ich möchte die
Telegramme möglichst kurz halten.Das, was Du beschrieben hast, ist eigentlich genau was ich suche.
ich bin halt kein gelernter Programmierer, sondern komme aus
der Hardwareecke.Das mit dem Design ist das größte Problem.
So etwas wird in den Büchern kaum oder gar nicht angesprochen.
Ich habe auch noch kein vernünftiges Buch zu diesem Thema gefunden.Wie würde das angesprochene Design in einem einfachen Beispielcode aussehen?
Ich habe eine zentrale Klasse, wo entsprechende Instanzen der anderen Klassen
angelegt sind und auch die Kommunikation der Klassen untereinander über
"Durchreichemethoden" erledigt wird.
z.B.- im Fenster einer Klasse wird ein Button gedrückt und ein Slot ausgelöst.
- dann sende ich ein Signal in die zentrale Klasse
- der dort aufgerufene Slot ruft dann eine Methode einer anderen per
Instanz eingebundenen Klasse auf( wie ich von einer Klasse sofort in die andere Klasse komme, habe
ich noch nicht herausgefunden, anscheinend geht das nicht (Instanz))Dort könnte ich auch die Datenklasse einbinden, bloß wie kommen die Daten in
die anderen Klassen, um dann auf diese zuzugreifen ?
Vor allem, da die Slots nicht direkt vom Programm, sondern von der QT Lib
bei einer Aktion im Hintergrund aufgerufen wird.Du hast Referenzen erwähnt, da muß ich mich mal einlesen; bisher habe
ich diese nicht benutzt.mfg
Michael J