Hallo zusammen,
ich versuche auf meinem M4-Cortex je nach Menü-Einstellung
unterschiedliche Funktionalitäten darzustellen.
Bisher habe ich es so realisiert, dass ich je eine eigene Klasse für die
Funktionalität erstellt habe. Dort gibt es immer wieder die gleichen
Methoden jedoch mit unterschiedlichem Funktionsinhalt.
Aufgerufen wurde das Ganze, von einer "Steuer"-Klasse mit einer ewig
langen SWITCH/CASE-Wüste. Und das jeweils für die 8 verschiedenen
Aufrufe.
Nun muss diese SWITCH/CASE-Wüste jedesmal angepasst werden, wenn ich
eine neue Funktionalität einbauen möchte. Und ich möchte viele Versionen
mit unterschiedlicher Zusammenstellung erstellen.
Nun dachte ich mir, es wäre einfacher alles über ein Array-of-functions
zu steuern. Einfach statt der SWITCH/CASE einen Aufruf mit dem
entsprechenden Index.
Nur wie bekomme ich die Klassen bzw. die Methoden in ein Array? Und wie
kann ich sie dann aufrufen?
Ich hab mir schon eine Klasse mit virtuelle Methoden für die
Array-Definition gebaut, komm aber damit nicht weiter.
Hab nun schon einige Stunden zusammen mit Tante Google verschiedene
Sachen ausprobiert. Nix wollte funktionieren.
Ja, Projekte und Code ist wohl nicht ganz korrekt. Das kann ein Mod
sicher noch verschieben.
Eventuell könnte dir das Observer Design Pattern weiterhelfen.
http://www.philipphauer.de/study/se/design-pattern/observer.php
In diesem Beispiel wäre der Zeitungsverlag dein Menü und die Abonnenten
wären deine Funktionsklassen.
Gruß Bernhard
Hermi schrieb:> Nur wie bekomme ich die Klassen bzw. die Methoden in ein Array? Und wie> kann ich sie dann aufrufen?
Wenn die Funktionen keine Parameter haben, reichen in der Regel function
pointer:
Wenn die einzelnen Klassen von einer gemeinsamen Basisklasse abgeleitet
sind und die gleichartigen aufzurufenden Methoden virtuell sind, sollte
das auch ohne switch und ohne explizite Funktionszeiger gehen.
Tut mir leid, wenn's in falsche Forum gerutscht ist. Welches wäre denn
das richtige?
@Admin: bitte dahin verschieben. Danke.
Bernhard R. schrieb:> Eventuell könnte dir das Observer Design Pattern weiterhelfen.
Das denke ich ist etwas übers Ziel hinausgeschossen. Es soll ja auch
noch relativ Speichersparend bleiben. Ist ja "nur" ein M4. Und geht das
in C++ überhaupt?
Torsten R. schrieb:> Wenn die Funktionen keine Parameter haben, reichen in der Regel function> pointer
Soweit richtig. Das funktioniert bei mir auch. Sogar mit Parameter, wenn
alle die gleichen Parameter haben.
Nur hagelt es Fehlermeldungen wenn die Funktionen in den verschiedenen
Klassen versteckt sind.
1
classCommFunct1{
2
publicunsignedcharinit(intparameterNum){
3
// code
4
}
5
};
6
classCommFunct2{
7
publicunsignedcharinit(intparameterNum){
8
// code
9
}
10
};
11
classCommFunct3{
12
publicunsignedcharinit(intparameterNum){
13
// code
14
}
15
};
Yalu X. schrieb:> Wenn die einzelnen Klassen von einer gemeinsamen Basisklasse abgeleitet> sind und die gleichartigen aufzurufenden Methoden virtuell sind, sollte> das auch ohne switch und ohne explizite Funktionszeiger gehen.
Und wie? Genau das war meine Frage. :-)
Hermi schrieb:> Und wie? Genau das war meine Frage. :-)
In dem Du (im obigen Beispiel) die Zeiger auf Funktionen durch Zeiger
auf Instanzen der von der Basisklasse abgeleiteten Klassen ersetzt.
Alternativ könntest Du auch mit std::function<> alles auf einen Typen
bringen, allerdings kann es dann sein, dass std::function<> dynamischen
Speicher verwendet, was für Deinen Anwendungsfall eigentlich nicht nötig
ist.
Warum möchtest Du einen Funktion durch eine Klasse abstrahieren? Haben
die "Funktionen" einen Zustand, der zwischen zwei Aufrufen erhalten
bleiben muss? Wenn ja, müssen sich dann nicht evtl. sogar mehrere
Funktionen den selben Zustand teilen?
Torsten R. schrieb:> Warum möchtest Du einen Funktion durch eine Klasse abstrahieren? Haben> die "Funktionen" einen Zustand, der zwischen zwei Aufrufen erhalten> bleiben muss? Wenn ja, müssen sich dann nicht evtl. sogar mehrere> Funktionen den selben Zustand teilen?
Die Klassen haben insgesamt 5 Funktionen. Um die Übersichtlichkeit zu
bewahren, haben alle die selben Methodennamen. Die Zustände sollen
zwischen den Aufrufen erhalten bleiben und evtl auch zwischen den
Funktionen einer Klasse geshared werden. Aber immer nur innerhalb der
Klasse.
Alle übergeordneten Aktionen werden von der Steuerklasse über die
Rückgabewerte und Parameter ausgeführt.
Torsten R. schrieb:> Zeiger> auf Instanzen der von der Basisklasse abgeleiteten Klassen ersetzt
hast du ein Code-Beispiel dazu wenn die Klassen so aussehen:
Da bekomme ich folgende Fehlermeldung:
Error: Conversion to inaccessible base class "CommFunctEltern" is not
allowed in "main.cpp"
Torsten R. schrieb:> P.S. in C++ hat man Konstruktoren für die Initialisierung.
Mein init hat nix mit der Klasseninitiatilisierung zu tun, sondern mit
der funktionsgesteuerten Hardwareinitialisierung.
Hermi schrieb:> Da bekomme ich folgende Fehlermeldung:> Error: Conversion to inaccessible base class "CommFunctEltern" is not> allowed in "main.cpp"
In welcher Zeile sollte das sein? Dass könnte nur der Fall sein, wenn Du
(wie in Deinem Beispiel) weiterhin private von der Basis-Klasse erbst.
Torsten R. schrieb:> Hermi schrieb:>> Da bekomme ich folgende Fehlermeldung:>> Error: Conversion to inaccessible base class "CommFunctEltern" is not>> allowed in "main.cpp">> In welcher Zeile sollte das sein? Dass könnte nur der Fall sein, wenn Du> (wie in Deinem Beispiel) weiterhin private von der Basis-Klasse erbst.
Es ist in der Zeile, in der die Zuweisung des Klassenobjekts in die
struct erfolgt.
Ich steh jetzt etwas auf der Leitung. Welche private vererbe ich.
Ich hab mal die Echte Klassenbeschreibung hier:
default inheritance in C++ ist für classes private. CommFunct ist also
eine private Basisklasse. Damit kann niemand (ausser Testmodul selbst)
ein Testmodul da einsetzen, wo ein CommFunct gefordert ist. Du möchtest:
Danke!
So läufts. Again what learned
Ich hab das ganze noch als Array aufgesetzt statt des struct. Damit spar
ich mir die Auswahlschleife. Von der Auswahlfunktion kommt sowieso eine
fortlaufende Nummer als uint8 zurück.
Hermi schrieb:> Ich hab das ganze noch als Array aufgesetzt statt des struct. Damit spar> ich mir die Auswahlschleife. Von der Auswahlfunktion kommt sowieso eine> fortlaufende Nummer als uint8 zurück.
Ich überlege gerade, ob es Sinn macht, wenn deine Funktionsklassen
ihren Callback bei der Steuer-Klasse anmelden. Dann müsstest du
beim Hinzufügen neuer Funktionen nur die Funktionsklasse schreiben,
alles andere wäre sozusagen generisch implementiert. Nur so ein Gedanke,
ich hab jetzt auch nicht den ganzen Thread gelesen, weiß auch nicht, ob
das mit
anderen Konzepten bei dir kollidiert...
Hermi schrieb:> Ich hab mir schon eine Klasse mit virtuelle Methoden für die> Array-Definition gebaut, komm aber damit nicht weiter.
Du solltest die Steuer-Klasse mit virtuellen Methoden bauen, dann ist
die vtable dein Array, ganz versteckt.
Callback nennt man solche Funktionen aber nicht.
Eine Callback-Funktion kommt von woanders. Ihre Adresse wird dorthin
übergeben. Damit man nicht bloss eine C Funktion sondern eine C++
Memberfunktion aufrufen willst, dann brauch man zusätzlich den self
Pointer, den ma neben der callback Funktionsadresse auch übergeben
müstte.
Guido schrieb:> Ich überlege gerade, ob es Sinn macht, wenn deine Funktionsklassen> ihren Callback bei der Steuer-Klasse anmelden. Dann müsstest du> beim Hinzufügen neuer Funktionen nur die Funktionsklasse schreiben,> alles andere wäre sozusagen generisch implementiert. Nur so ein Gedanke,> ich hab jetzt auch nicht den ganzen Thread gelesen, weiß auch nicht, ob> das mit> anderen Konzepten bei dir kollidiert...
Da das ganze auf einem Arm-M4-Cortex-Controller läuft und alles bei
Compilezeit definiert ist, wäre das Anmelden der Funktion nur zusätzlich
Code-Speicher-Ausführungszeit.
Leider finde ich die Platzierung des Beitrags im PC-Programmierungsforum
etwas unglücklich. Aber soll wohl so sein.
MaWin schrieb:> Callback nennt man solche Funktionen aber nicht.
Gut, aber wie heißts dann?
MaWin schrieb:> Hermi schrieb:>> Ich hab mir schon eine Klasse mit virtuelle Methoden für die>> Array-Definition gebaut, komm aber damit nicht weiter.>> Du solltest die Steuer-Klasse mit virtuellen Methoden bauen, dann ist> die vtable dein Array, ganz versteckt.
Ich denk, mein Weg war nicht ganz verkehrt. Nur leider mangels
Wissen/Erfahrung nicht ganz fertig. Dank Torsten Robitzki läufts jetzt
und ist auch relativ schlank.
Ich habe meine Funktionen in eigenen abgeschlossenen Klassen/Files, Die
Steuerklasse ist auch schön separiert und ich kann alles, nach Bedarf,
in meinem main.cpp zusammennageln.