Guten Morgen,
für einen STM32F3 möchte ich mein Programm in C++ schreiben. Dazu möchte
ich eine Klasse Application als globales Singleton implementieren, in
der alle Variablen und Objekte, die von dem Programm verwendetet werden
enthalten sind. Mein Problem ist, wie gestaltet man die Initialisierung
der Objekte? Beim Anlegen der eines Objekts von Application werden
automatisch die Konstruktoren der Members aufgerufen.
Eigentlich möchte ich den Konstruktor der jeweiligen Klassen dazu
verwenden, die Initialisierung durchzuführen.
Ich hätte zwei Ansätze zur Lösung meines Problems.
1. Alle Members von Application als Pointer deklarieren und im
Konstruktor bzw. in einer initializeApplication()-Funktion als static
anlegen und initialisieren um sie dann den Pointern zuzuweisen.
2. Jede Klasse erhält eine Funktion initialize(...) mit der die
Initialisierung durchgeführt wird. So könnte ich den Zeitpunkt der
Initialisierung von der Erstellung des Objekts unabhängig machen.
Gibt es auch andere Möglichkeiten das zu lösen?
Viele Grüße
Moin,
das kommt darauf an was du erreichen willst. Bei Variante 1 werden die
Konstruktoren in der Reihenfolge der statischen Definitionen der Objekte
ausgeführt. Falls eines der Objekte eine Peripherie behandelt ist es
meißt ungünstig wenn die eine Peripherie vor der einer Anderen
initialisiert wird.
PWM vor dem CLOCK oder so.
Was bezweckst du mit dem Entwurf als Singleton? Aus Spaß an der Freude?
Bei einzigartigen Peripherieteilen macht ein Singleton für die
Handlingklasse dieser Peripherie Sinn aber für die Application? Die ist
doch schon im Controller gekapselt :).
Beschreib mal das Design was du im Kopf hast etwas genauer.
Gruß
Tec
Tec N. schrieb:> Was bezweckst du mit dem Entwurf als Singleton? Aus Spaß an der Freude?> Bei einzigartigen Peripherieteilen macht ein Singleton für die> Handlingklasse dieser Peripherie Sinn aber für die Application? Die ist> doch schon im Controller gekapselt :).
Meist wird einem ja eingeredet, wie böse globale Variablen sind. Da
kommt so ein Singleton gerade recht, um das gute Gefühl zu bekommen,
diese vermieden zu haben. Man hat zwar keinen wirklichen Vorteil davon,
aber immerhin die Regel beachtet.
Also syntaktischer Zucker um globale Variablen zu verbergen, die
trotzdem faktisch nur globalen Variablen bleiben - auf die man nur etwas
komplizierter zugreifen muss. Wer's mag ...
Jay schrieb:> Also syntaktischer Zucker um globale Variablen zu verbergen, die> trotzdem faktisch nur globalen Variablen bleiben - auf die man nur etwas> komplizierter zugreifen muss. Wer's mag ...
Das ist halt das typische Vorgehen wenn jemand OOP einsetzen will ohne
OOP verstanden zu haben. Evt. rührt daher auch der vielerorts schlechte
Ruf von OOP.
Tec N. schrieb:> Was bezweckst du mit dem Entwurf als Singleton?
Mit dem Singleton möchte ich verhindern, dass mehrere Instanzen von
Application erzeugt werden können (ich kann zwar bestimmen wie viele
Objekte von Application in der main.cpp angelegt werden, aber ich dachte
mir, so ist es "sauberer" programmiert). Wie würdet Ihr das machen?
Tec N. schrieb:> Beschreib mal das Design was du im Kopf hast etwas genauer.
Puuuhh, also...
Das ganze wird ein bi-direktionaler Tiefsetzsteller (Aufbau als
4-Quadrantensteller) für meine BA (Elektrotechnik).
Die Idee ist, die STM32 HAL-Treiber in Interfaces zu kapseln, die noch
"relativ" generisch sind (ist alles ausbaufähig, aber dazu fehlt mir in
der BA die Zeit). Daraus wiederum leite ich dann die spezifischen
Hardware-Klassen ab, die ich zur Konfiguration und Steuerung der
Peripherie verwende. Zusätzlich gibt es dann noch eine Klasse für die
Tiefsetzsteller- bzw. DC/DC-Wandler Funktionalität. Im Anhang siehst
Du/seht Ihr, wie mein Klassendiagramm bisher aussieht (bitte nicht
schlagen, ich bin SEHR neu im Gebiet der Objekt orientierten
Programmierung, das Wort Klassendiagramm gehört erst seit ein paar
Wochen zu meinem Wortschatz ;)). Viele der Klassen sind noch nicht
fertig. Aber ich hoffe man kann daraus die Richtung in die das Ganze
gehen soll erkennen.
Viele Grüße und danke für die schnellen Antworten :)
muuuhhh schrieb:> Mit dem Singleton möchte ich verhindern, dass mehrere Instanzen von> Application erzeugt werden können (ich kann zwar bestimmen wie viele> Objekte von Application in der main.cpp angelegt werden, aber ich dachte> mir, so ist es "sauberer" programmiert). Wie würdet Ihr das machen?
das kannst du doch auch verhindern wenn du das einfach programmierst,
ohne zusätzliche Klasse "Applikation". Indem es nur eine Instanz davon
gibt. Oder glaubst du, dass du dynamisch irgendwelche Dinge erzeugen
willst?...
muuuhhh schrieb:> Puuuhh, also...> Das ganze wird ein bi-direktionaler Tiefsetzsteller (Aufbau als> 4-Quadrantensteller) für meine BA (Elektrotechnik).> Die Idee ist, die STM32 HAL-Treiber in Interfaces zu kapseln, die noch> "relativ" generisch sind (ist alles ausbaufähig, aber dazu fehlt mir in> der BA die Zeit). Daraus wiederum leite ich dann die spezifischen> Hardware-Klassen ab, die ich zur Konfiguration und Steuerung der> Peripherie verwende. Zusätzlich gibt es dann noch eine Klasse für die> Tiefsetzsteller- bzw. DC/DC-Wandler Funktionalität. Im Anhang siehst> Du/seht Ihr, wie mein Klassendiagramm bisher aussieht (bitte nicht> schlagen, ich bin SEHR neu im Gebiet der Objekt orientierten> Programmierung, das Wort Klassendiagramm gehört erst seit ein paar> Wochen zu meinem Wortschatz ;)). Viele der Klassen sind noch nicht> fertig. Aber ich hoffe man kann daraus die Richtung in die das Ganze> gehen soll erkennen.
Prinzipiell sieht dein Klassendiagramm nicht schlecht aus.
Du musst aber aufpassen. Klassen auf nem µC haben manchmal ein unschönes
Verhalten(implizite Aufruftiefe von Funktionen, Vererbung etc.). Da
übersieht man recht schnell Dinge, was sich dann in der Geschwindigkeit
der Applikation wiederspiegelt.
Ich persönlich würde es so nicht machen. Ich würde das nicht extra in
die Klasse Applikation hineinkapseln, das wirkt doch sehr nach
Selbstzweck und nicht nach dem Ansatz, den man eher IMHO verfolgen
sollte: OOP dort wo's Sinn macht und dir wirklich einen Vorteil schafft.
Man kann auch ohne C++ Architekturen schaffen die funktionieren
(Autosar).
Vererbung würde ich versuchen ganz raus zu lassen. Das kostet dich
Laufzeit, welche aber u.U. nicht relevant ist(das kannst nur du
einschätzen).
Ich hab bis jetzt nur die STD_Peripheral von STM genutzt, die ist ja
eigentlich bereits vernünftig in "Objekte" gekapselt, auch wenn man dort
nicht sowas schönes wie Überladung zur Verfügung hat.
Beim CAN: wenn du z.B. nur einen CAN zur Verfügung hast (bzw. nutzt)
macht es in C++ manchmal Sinn, die Klasse zwar zur Verfügung zu haben,
aber anstatt Instanzen davon zu erzeugen (nähmlich genau 1), die
Funktionen und Variablen static zu deklarieren. Spart dir auch
Initialisierungsarbeit.
muuuhhh schrieb:> (bitte nicht> schlagen, ich bin SEHR neu im Gebiet der Objekt orientierten> Programmierung, das Wort Klassendiagramm gehört erst seit ein paar> Wochen zu meinem Wortschatz ;))
Das versteh ich nicht ganz. Ist das eine explizite Anforderung an deine
BA? In der BA soll man doch eigentlich das im Studium erlernte
selbstständig umsetzen und dabei zeigen, wie gut man diese umsetzen
kann. Wenn du im ganzen Studium noch nichts von Klassen gehört hast
(bzw. OOP), warum muss du dann unbedingt alles OOP machen? Dein Problem
kann man genauso gut in C lösen, dort kann man auch vernünftig arbeiten.
Ich kann ui nur zustimmen.
Mit dem OOP halte ich das so, dass ich doppelten Code vermeide. Dann ist
man oft an den sinnvollen Stellen gezwungen OOP einzusetzen.
Tec N. schrieb:> Mit dem OOP halte ich das so, dass ich doppelten Code vermeide. Dann ist> man oft an den sinnvollen Stellen gezwungen OOP einzusetzen.
wie kann man denn mit OOP doppelte Code Vermeiden, was bei normalen
Prozeduren nicht geht?
Peter II schrieb:> Tec N. schrieb:>> Mit dem OOP halte ich das so, dass ich doppelten Code vermeide. Dann ist>> man oft an den sinnvollen Stellen gezwungen OOP einzusetzen.>> wie kann man denn mit OOP doppelte Code Vermeiden, was bei normalen> Prozeduren nicht geht?
Doofe Frage, sorry. Du kannst jedes OOP Konzept auch irgendwie ohne
explizite OOP Unterstützung nachprogrammieren. Das ist ja wohl ein alter
Hut.
Peter II schrieb:> wie kann man denn mit OOP doppelte Code Vermeiden, was bei normalen> Prozeduren nicht geht?
speziell C++ vs. C? Dann Überladung. Vielleicht meinte er das auch.
muuuhhh schrieb:> Viele der Klassen sind noch nicht> fertig. Aber ich hoffe man kann daraus die Richtung in die das Ganze> gehen soll erkennen.
Warum gibt es denn bitte 2 Klassen für das ADC Interface.
Du hast 1 Klasse ADC Interface, erzeugst aber während der
Programmausführung 2 Instanzen davon (mit C++14 kann man das auch zur
Kompilierzeit machen, dann muss das ganze aber statisch sein, könnte
evtl. für dich was sein)
muuuhhh schrieb:> Im Anhang siehst> Du/seht Ihr, wie mein Klassendiagramm bisher aussieht (bitte nicht> schlagen, ich bin SEHR neu im Gebiet der Objekt orientierten> Programmierung, das Wort Klassendiagramm gehört erst seit ein paar> Wochen zu meinem Wortschatz ;)).
nochwas: Als Buchempfehlung (fande ich besser als unsere SE VL, und ich
hab Informatik studiert): UML 2 Glasklar (ohne Werbung machen zu
wollen).
Für dich ist es (vermutlich, sollte eigentlich dein Betreuer dir sagen,
darauf hinweisen), wenn du dir nur ein grobes Klassendiagramm aufmalst.
Muss auch nicht formal oder so sein, da gehts eher um das, das du weißt
was wo ist. In deine BA kannst das Riesending mit allen Methoden etc. eh
nicht reinpacken. Dort ist auch nur eine Übersicht Sinnvoll (welche
Klassen gibt es und wie hängen die zusammen). Außerdem noch so ein
grobes Architekturbild, wo nochmal ersichtlich ist, wo die verschiedenen
Schichten sind, wie diese zusammenhängen. Versinnbildlicht (IMHO) den
Zusammenhang und die Kapselung oft besser (Klasse A darf auf B
zugreifen, die auf C zugreift. Aber A darf nicht auf C zugreifen z.B.).
Solange du keinen Code aus deinem Diagramm erzeugen willst macht es
wenig Sinn, das so detailiert zu machen.
Oftmals sind Datenfluss bzw. Kontrollflussgraphen, Activitydiagramme,
Sequenzdiagramme und Kommunikationsdiagramme (evtl. wirklich was für
dich, nutzt ja auch CAN etc.) sinnvoll, die sind oftmals für den Leser
interessanter als Klassendiagramme, weil man einfach schneller besser
abschätzen kann, was passiert in welchem Zusammenhang und wie passsiert
das.
Als Tipp ;)
muuuhhh schrieb:> Mit dem Singleton möchte ich verhindern, dass mehrere Instanzen von> Application erzeugt werden können (ich kann zwar bestimmen wie viele> Objekte von Application in der main.cpp angelegt werden, aber ich dachte> mir, so ist es "sauberer" programmiert).
Und welche böse Mann soll sich Nachts an deinen Computer schleichen und
heimlich Code zu deinem Quelltext hinzufügen, so dass eine weiter
Instanz von Application erzeugt wird?
> Oder glaubst du, dass du dynamisch irgendwelche Dinge erzeugen> willst?...
Das möchte ich eigentlich nach Möglichkeit vermeiden.
> Ist das eine explizite Anforderung an deine> BA?
Nein. Ich wollte das lernen. Einen anderen Grund hat es eigentlich
nicht.
Ich fand den Ansatz schön, dass man sich mit Interfaces eine Art
Standard HAL schafft, die von der Plattform unabhängig wird. Damit wäre
mein Programm auch auf anderen Controllern mit ARM Architektur
lauffähig. Dazu müsste man natürlich Gemeinsamkeiten von allen
Mikrocontrollern bzw. in meinem Fall ARM Cortex-M4F Controllern und
deren Periphere herausfinden und diese jeweils für die virtuellen
Funktionen des Interfaces umsetzen.
> Vererbung würde ich versuchen ganz raus zu lassen. Das kostet dich> Laufzeit, welche aber u.U. nicht relevant ist(das kannst nur du> einschätzen).
Wieso ist das so? Ich weiß leider nicht genau, wie der Compiler das
umsetzt bzw. was dann während der Laufzeit des Programms passiert. Geht
es dabei um die virtuellen Funktionen?