Hallo Leute,
ich benutze in meinem C++ Programm eine C-Bibliothek.
Diese benutzt Callbacks und zwicngt mich im C++ immer über einen Umweg
einer Statischen Member-funktion. Diese Statische Member-Funktion ruft
dann die eigentliche Routine.
Ich möchte über eine Wrapper-Klasse das für mein Programm eleganter, auf
C++ Weise lösen. Dabei die statische Member-Funktion vermeiden. Komme
aber nicht weiter.
Ich schaue hier in die C++ Spezifikation
https://en.cppreference.com/w/cpp/utility/functional/bind , stell mich
aber zu blöd an, die richtigen Sequenzen zu treffen.
Könnt ihr mir helfen? Die betreffenden Stellen sind mit ??? markiert.
Unten mein minimalistischer Code. Beispielhaft ist die Benutzung in C
und C++ ruft C. Was jetzt fehlt ist ist die korrekte Implementierung der
C++-Wrapper Klasse.
Vielen Dank schon mal für eure Anmerkungen ... :-)
Danke und Grüße, Adib.
--
und jetzt mein Code
1
#include<iostream>
2
#include<functional>
3
usingnamespacestd;
4
5
#include<stdint.h>
6
#include<stddef.h>
7
8
// -------- C API here
9
typedefstruct{
10
void*cb_object;// pointer to object
11
void(*cb_function)(void*,char*,size_t);// pointer to function
The A. schrieb:> Hallo Leute,>> ich benutze in meinem C++ Programm eine C-Bibliothek.> Diese benutzt Callbacks und zwicngt mich im C++ immer über einen Umweg> einer Statischen Member-funktion. Diese Statische Member-Funktion ruft> dann die eigentliche Routine.>> Ich möchte über eine Wrapper-Klasse das für mein Programm eleganter, auf> C++ Weise lösen. Dabei die statische Member-Funktion vermeiden. Komme> aber nicht weiter.
Das C++-Pendant sind virtuelle Memberfunktionen. Ich würde also eine
abstrakte Basisklasse schreiben und die statische Memberfunktion dort
genau einmal definieren.
Hallo,
inwieweit ist den die jetzige Lösung besser als die Vorherigen? Elegant
wäre es doch, wenn die Klasse Foopp den gewünschten Aspekt der C Lib
abstrahiert, z. B.:
The A. schrieb:> Habs jetzt mit std::bind gelöst:
Wie Rolf oben geschrieben hat werden in C++ virtuelle Funktionen für
"Interfaces" benutzt. Das Interface wird abstrakt definiert...
1
structInterface
2
{
3
virtualvoidsome_service(char*,size_t)=0;
4
};
...und dann für die konkrete Umsetzung implementiert (abgeleitet).
In deinem Code habe ich weder verstanden, wie dein C-Interface aussieht,
noch wie deine vorgeschlagene Art der C++-"Kapselung" die Situation
verbessert. Tatsächlich wird dein Code dadurch noch unverständlicher.
Das mag jetzt am konkreten Beispiel liegen. Ich nehme mal an, du weisst
was du da tust und worin deine "Verbesserung" liegt. Dann ist alles gut.
Für einen Aussenstehenden wie mich ist dein Code ein Beispiel wie man
nicht programmieren sollte. -- Das ist jetzt aber nicht böse gemeint.
Mikro 7. schrieb:
...
> Wie Rolf oben geschrieben hat werden in C++ virtuelle Funktionen für> "Interfaces" benutzt. Das Interface wird abstrakt definiert...
...
>
Hallo Mikro 7,
Bin eher in der C-Welt zuhause und dankbar für Anregungen.
Die C-Library ist ein Parser, der fertige Datenpakete im Callback
zurückmeldet.
Der Parser wird gespeist aus einer Datenquelle, einem zB UART Interface.
Der Parser kennt den eigentlichen Dateninhalt nicht.
1
while(uart_ready()){
2
foo_process(&ctx,uart_read());
3
}
Der Callback ist wie eine DataReady Funktion, die die Daten eine Schicht
zurück liefert. Un dann applikationsspezifisch interpretiert und
verarbeitet.
Der C-Callback implementiert dabei eine Art Observer Pattern.
Im C++ hatte ich dabei die Schwierigkeit, dass ich zusätzlich eine
statische Methode definieren musste, als Ziel für den Callback. Um dann
die eigentliche Eventbehandlung aufzurufen.
(im Qt hätte ich den Signal/Slot Mechanismus genommen)
Die Behandlung der Daten ist je nach Applikations und Schnittstelle
unterschiedlich.
Also die Klasse die die Daten behandelt sollte hat ein Parser und
nicht ist ein Parser sein. Daher "gibt es eine Parser-Instanz" und
nicht "implementiert ein Parser-Interface".
Was gäbe es denn da noch für Möglichkeiten?
Danke und Grüße.
Hallo!
Du hast also für eine Datenquelle (bspw. UART) einen Reader der Pakete
aus dem Bitstream baut und einen Parser der die Pakete liest. Reader und
Parser sollen entkoppelt werden. -- Das ist eine klassische
Programmieraufgabe.
Bei dir gibt es mehrere Reader die mit dem gleichen Parser arbeiten
(oder umgekehrt?) Ein Ansatz in C++ zum Entkoppeln sind wie gesagt
Interfaces. Im folgenden Beispiel wird der Reader vom Parser entkoppelt:
1
structReader
2
{
3
structInterface
4
{
5
virtualvoidprocess(charconst*,size_t)=0;
6
};
7
Reader(Interface*consumer);
8
// ...
9
};
10
11
structParser:Reader::Interface{// ...
Man kann aber auch den Signal-Slot-Mechanismus aus Qt nehmen, oder sich
sowas selbst bauen, oder std::function nehmen, oder...
Was ich in deinem Beitrag nicht wirklich verstanden hatte, war dein
genaues Problem, und wie du es gelöst hast. Das gibt dein
Code/Beschreibung imho nicht her. (Und das war mein Punkt:
verständlichen Code schreiben.)
Wenn ich spekuliere, dein Problem war, dass du für deine
Callback-Signatur, also für...
1
void(*)(void*,char*,size_t)
...nicht den Weg gefunden hast direkt die Objektmethode...
1
void(T::*)(char*,size_t)
...zu benutzen, und statt dessen eine statische Methode eingeführt hast.
-- Müssen wir hier aber nicht weiter vertiefen.
Schönen Abend noch!