Huhu!
ich versuche ein Pointer-Array zu erstellen, welche verschiedene
Methoden unterschiedlicher Klassen aufnimmt. Allerdings scheitert es
schon daran, eine Methode einer einzigen Klasse aufzunehmen.
1
void(GUI::Widget::TextBox::*asdf)()=NULL;
2
asdf=&GUI::Widget::TextBox::Update;
3
4
if(asdf!=&GUI::Widget::TextBox::Update)
5
intb=1;
6
else
7
intc=2;
8
9
boold=asdf;
Der Code kompiliert ohne zu meckern, allerdings wird Update() nicht
angesprungen. Auch stimmen die Adressen nicht überein. Update hat bspws
0x8004a34 und asdf 0x8004a35. Das ist auch durchgehend so, die Pointer
haben immer die Adresse der Funktion + 1.
Habe auch schon gegoogelt, aber hat anscheinend nicht viel geholfen.
Hat jemand eine Idee? Ich benutze GCC 5.3.0 + GDB. Programm läuft auf
einem STM32F4.
Color::Green,Color::WhiteSmoke,Memory::Resource::Object::GetFont((char*)"MS Sans Serif 12pt"));
4
consoletb->Show();
5
6
bool(GUI::Widget::TextBox::*asdf)()=NULL;
7
asdf=&GUI::Widget::TextBox::Update;
8
boolb=consoletb->*asdf();
error : must use '.*' or '->*' to call pointer-to-member function in
'asdf (...)', e.g. '(... ->* asdf) (...)'
1> bool b = consoletb->*asdf();
Die Meldung verstehe ich allerdings nicht.
EDIT: Du bist ein Schatz, da muss eine Klammer hin :>
bool b = (consoletb->*asdf)();
Achso, es geht noch weiter :)
Erst mal danke, da saß ich gestern ein paar Stunden dran, du hast es mit
deinem 3 Zeiler geschafft mein Problem in einer Minute zu lösen :>
Ist es möglich auch Methoden verschiedener Klassen in einen Pointer zu
packen? So etwas in Richtung void? Warscheinlich eher weniger, soweit
ich mich informieren konnte?
Reginald L. schrieb:> Ist es möglich auch Methoden verschiedener Klassen in einen Pointer zu> packen?
Ja, wenn die Klassen von einer gemeinsamen Basisklasse abgeleitet sind.
Oder du musst mit Templates arbeiten. Kommt halt drauf an, wofür das
ganze gut sein soll. Willst du so eine Art Nachbau eines
signal/slot-Mechanismus machen?
> So etwas in Richtung void? Warscheinlich eher weniger, soweit ich mich> informieren konnte?
Dann würde ja die ganze Typsicherheit flöten gehen.
Reginald L. schrieb:> ich versuche ein Pointer-Array zu erstellen, welche verschiedene> Methoden unterschiedlicher Klassen aufnimmt.
Darf man fragen, was der Sinn der Sache ist?
Reginald L. schrieb:> Ist es möglich auch Methoden verschiedener Klassen in einen Pointer zu> packen?
Ja, das geht in gewissen Grenzen, indem man std::bind oder Lambdas
nutzt. Hierbei muss man allerdings bei der Zuweisung direkt die Instanz
mitgeben. Das Ergebnis ist sozusagen ein polymorpher Funktionszeiger:
>Ist es möglich auch Methoden verschiedener Klassen in einen Pointer zu
packen?
Das geht, wird aber beliebig hässlich und wackelig.
Wenn man die Klassen, auf deren Methoden man zugreifen will, nicht
selbst schreibt und so keine Interfaces einführen kann, kann man mit
std::function und std::bind etwas bauen:
Bei all diesen Features muss man sehr darauf achten, sie nicht
übertrieben einzusetzen. Die Möglichkeiten sind verlockend, aber man
kann sehr leicht völlig undurchdringliche Programmstrukturen bauen.
std::function ist auch nichts für extrem performancekritische
Anwendungen.
Schweinereien find ich toll :D.
Die Performance ist mir lediglich beim Zugriff auf die Memberfunktion
wichtig, da, bei Bedarf, in der Mainloop darauf zugegriffen wird. Die
Initialisierungen finden beim Programmstart statt.
Von std::function habe ich auch schon gehört, heute wirds mir aber schon
zu spät, morgen ist auch noch ein Tag.
So, ich habe mich jetzt ein wenig in std:function eingelesen,
Tom schrieb:> std::function ist auch nichts für extrem performancekritische> Anwendungen.
und das gefällt mir nicht so ganz. Gibt es noch andere Möglichkeiten? Es
geht lediglich um statische Methoden einer Klasse die in die Interrupts
eingebunden werden sollen. So eine Art lookuptable die der Interrupt
durchrennt.
Reginald L. schrieb:> Es> geht lediglich um statische Methoden einer Klasse die in die Interrupts> eingebunden werden sollen.
Ach statische Funktionen! Das macht die Sache viel einfacher. Da
kannst du ordinäre Funktions-Pointer nutzen, denn statische
Member-Funktionen verhalten sich effektiv wie freie Funktionen:
Niklas G. schrieb:> Das macht die Sache viel einfacher. Da> kannst du ordinäre Funktions-Pointer nutzen, denn statische> Member-Funktionen verhalten sich effektiv wie freie Funktionen:
Hui ging ja fix! Gerade erst gelesen.
Das mit dem Funktionspointer-Typ finde ich zumindest schonmal eleganter,
danke erstmal, ich mach mich ran :)
Niklas G. schrieb:> Ach statische Funktionen!
Ja, ich stehe gerade vor einer anderen Aufgabe, dachte nur, es wäre
unsinnig einen neuen Thread zu eröffnen, da das hier ganz gut reinpasst.
Das Problem mit der GUI Klasse ist geblieben, aber momentan noch auf
Eis.
Danke nochmal!
Reginald L. schrieb:> init(void(*irq_handler_func)(void))
Fehlt da nicht der Rückgabe-Typ...
Reginald L. schrieb:> Das mit dem Funktionspointer-Typ finde ich zumindest schonmal eleganter,
Ja das erhöht die Lesbarkeit enorm...
Reginald L. schrieb:> als dass ich sagen> könnte ob die Methode ansatzweise elegant ist.
So ist die Anzahl Callbacks halt auf 5 beschränkt... Etwas schlauer wäre
es, eine intrusive verkettete Liste zu machen. Der Benutzer legt dann
pro Callback-Funktion eine globale Instanz von Observer an:
1
#include<iostream>
2
3
// Funktionszeiger-Typ definieren für Callback-Funktion
Noch eleganter ist dann das komplette Observer-Pattern:
1
#include<iostream>
2
3
classPublisher;
4
5
// Abstrakte Basisklasse für Handler-Klassen
6
classObserver{
7
friendclassPublisher;
8
public:
9
virtualvoidevent()=0;
10
private:
11
Observer*next;
12
};
13
14
classPublisher{
15
public:
16
// Observer hinzufügen und verketten
17
voidaddObserver(Observer*o){
18
if(first)
19
o->next=first;
20
else
21
o->next=nullptr;
22
first=o;
23
}
24
// Alle Funktionszeiger aufrufen
25
voidcall(){
26
for(Observer*scan=first;scan;scan=scan->next){
27
scan->event();
28
}
29
}
30
private:
31
Observer*first=nullptr;
32
};
33
34
// Publisher für IRQ's anlegen
35
36
PublisherpubIRQ_EXTI9_5;
37
38
extern"C"voidEXTI9_5_IRQHandler(){
39
// Alle Funktionszeiger aufrufen
40
pubIRQ_EXTI9_5.call();
41
}
42
43
PublisherpubIRQ_TIM3;
44
45
extern"C"voidTIM3_IRQHandler(){
46
// Alle Funktionszeiger aufrufen
47
pubIRQ_TIM3.call();
48
}
49
50
// === User Code ===
51
52
classHandler1:publicObserver{
53
public:
54
virtualvoidevent(){
55
std::cout<<"Handler1::event\n";
56
}
57
}handler1;
58
59
classHandler2:publicObserver{
60
public:
61
virtualvoidevent(){
62
std::cout<<"Handler2::event\n";
63
}
64
}handler2;
65
66
intmain(){
67
pubIRQ_EXTI9_5.addObserver(&handler1);
68
pubIRQ_TIM3.addObserver(&handler2);
69
70
pubIRQ_EXTI9_5.call();
71
pubIRQ_TIM3.call();
72
}
So muss man gar nicht mehr mit Funktionspointern herumhantieren sondern
nutzt das wohlbekannte Observer Pattern. Einzige Modifikation ist hier
der "next" Pointer, um eine Liste aufzubauen.
Implementierung von Funktionen zum Entfernen von Observern sind dem
Leser überlassen ;-)
Niklas G. schrieb:> Fehlt da nicht der Rückgabe-Typ...
Ich war schlampig beim umtippen. Entschuldigung :P
Na da hasste mir ne Steilvorlage geliefert, da muss ich ja gar nicht
mehr nachdenken ;)