c++ (arduino): gegenseitiger aufruf von memberfunktionen
wergor 15.10.2014 - 17:22 3460 9
wergor
connoisseur de mimi
|
ich habe in meinem arduino projekt die klassen SerialHandler und Device: SerialHandler - sendet und empfängt nachrichten über die serielle verbindung, ruft memberfunktionen von der Device- instanz auf. Device - macht sachen (z.b. bewegen von schrittmotoren).
die instanzen der beiden klassen sind global definiert. damit SerialHandler auf Device zugreifen kann, ist der header Device.h in SerialHandler.h included und die Device instanz mit #extern deklariert. wenn ein kommando hereinkommt, ruft SerialHandler die entsprechende memberfunktion der Device klasse auf, wartet bis die fertig ist und sendet dann eine antwort.
soweit funktioniert das auch wunderbar. jetzt will ich aber dass die SerialHandler nicht auf die Device klasse warten muss, deshalb soll die Device klasse nach getanener arbeit von sich aus das senden der antwort veranlassen. damit die Device klasse auf member der SerialHandler klasse zugreifen kann, muss ich in der Device.h die SerialHandler.h includen und mit #extern die SerialHandler instanz deklarieren. da spielt aber der compiler nicht mit (Device includes SerialHandler includes Device includes...).
die einfachste lösung wäre Device selbst die antworten schicken zu lassen, aber ich würde das lieber den SerialHandler machen lassen. gibts da eine möglichkeit?
|
that
ModeratorHoffnungsloser Optimist
|
jetzt will ich aber dass die SerialHandler nicht auf die Device klasse warten muss, deshalb soll die Device klasse nach getanener arbeit von sich aus das senden der antwort veranlassen. Das Senden der Antwort in der anderen Klasse zu machen ist nicht schwierig, aber das "dass SerialHandler nicht auf Device warten muss" - wie hast du dir das vorgestellt? Du musst ja trotzdem die Funktion aufrufen, und die kommt erst zurück wenn sie fertig ist.
|
wergor
connoisseur de mimi
|
dafür habe ich eine library. Die funktionen die serialhandler aufruft setzen nur neue ziele / parameter für die schrittmotoren. Im main loop wird eine funktion run() aufgerufen die die schrittmotoren einen schritt vor oder zurück gehen lässt wenns nötig ist und dann returned, dadurch ist der code nicht durch warten auf das device blockiert. void loop()
{
serialHandler.parseInput();
device.run();
}
|
that
ModeratorHoffnungsloser Optimist
|
Ich weiß nicht wie das bei Arduino ist (das baut ja ein bisserl Logik um deine Funktionen drumherum), aber in "normalem" C++ gibts .h und .cpp Files. Du kannst in jedem .cpp jedes .h #includen und es gibt keine endlosen Zyklen. Was ist überhaupt "#extern"?
|
wergor
connoisseur de mimi
|
ich bin mir gerade nicht sicher dass das problem durch endlose zyklen entsteht. wenn ich in der Device.h die SerialHander.h include, wirft der compiler folgende fehlermeldung: Device.h:In file included from
Device.cpp:from
SerialHandler.h:17: error: 'Device' does not name a type
Error compiling
zeile 17 der SerialHandler.h: extern Device device;
@extern: (natürlich ohne #, sry) http://stackoverflow.com/a/10422050 This comes in useful when you have global variables. You declare the existence of global variables in a header, so that each source file that includes the header knows about it, but you only need to “define” it once in one of your source files.
To clarify, using extern int x; tells the compiler that an object of type int called x exists somewhere. It's not the compilers job to know where it exists, it just needs to know the type and name so it knows how to use it. Once all of the source files have been compiled, the linker will resolve all of the references of x to the one definition that it finds in one of the compiled source files. For it to work, the definition of the x variable needs to have what's called “external linkage”, which basically means that it needs to be declared outside of a function (at what's usually called “the file scope”) and without the static keyword.
|
Hansmaulwurf
u wot m8?
|
edit: Sorry, jetzt hab ichs überissen, und kann nix beitragen
Bearbeitet von Hansmaulwurf am 16.10.2014, 22:44
|
wergor
connoisseur de mimi
|
@wergor : Warum schreibst nicht einfach eine memberfunktion für "Device" die Parameter vom Serial übernehmen kann? Dann brauchst nicht im Kreis linken. ich habe mehrere device klassen. die SerialHandler klasse soll die commands an die jeweils richtigen devices weitergeben.edit: Sorry, jetzt hab ichs überissen, und kann nix beitragen np
|
PuhBär
Schau ned so genau
|
Forwarddeclaration evtl? Weiss nicht ob das dann mit extern funktioniert.
Würde im Serialhandler.h einfach ein "class Device;" hinschreiben, anstatt Device.h zu inkludieren.
Solange du Serialhandler nicht als Member in Device brauchst, kann der incomplete type von Device als Parameter für eine Funktion verwendet werden. Inkludieren kannst du Serialhandler.h dann im Device.cpp.
|
Paxi
Overclocking Team Member
|
Forwarddeclaration würde eben nur funktionieren sofern man noch keine Methode der Klasse aufrufen will bzw generell nur solange man nur auf Pointer der Klasse referenziert weil sonst der Compiler die exakte Größe kennen muss, was er bei einer Forwarddeclaration noch nicht tut. Ich würde zwar jetzt kein Geld darauf wetten aber ich bin mir relativ sicher, dass es für den Compiler kein Problem darstellt, wenn zwei Header sich gegenseitig includen und man einen davon included. Wichtig ist jedenfalls nur, dass beide Header einen Header guard haben. Also sowas wie: #ifndef HEADER_H
#define HEADER_H
// code
#endif
Sofern möglich sollte man Header aber immer erst im .cpp inkludieren, wie bereits gesagt wurde. Bzg extern: Es spricht nichts dagegen extern in diesem Zusammenhang zu verwenden, sofern man auf eine existierende Variable in einer anderen Translation Unit referenziert. Ich persönlich bevorzuge aber eher solche Konstrukte: // Header
static Instance* GiveMeTheInstance();
// Cpp
static Instance* GiveMeTheInstance() {
static Instance instance;
return &instance;
}
Sowas habe ich in C++ schon ein paar mal verwendet (auch wenn ich da sowas wie Singletons eher vermeide), wird wohl in C auch so funktionieren.
|
wergor
connoisseur de mimi
|
danke für die antworten! forward declaration direkt vor den extern statements in beiden header files hat das problem gelöst. class SerialHandler;
extern SerialHandler serialHandler;
Ich würde zwar jetzt kein Geld darauf wetten aber ich bin mir relativ sicher, dass es für den Compiler kein Problem darstellt, wenn zwei Header sich gegenseitig includen und man einen davon included. Wichtig ist jedenfalls nur, dass beide Header einen Header guard haben. Also sowas wie:
#ifndef HEADER_H
#define HEADER_H
// code
#endif
header guards hatte ich schon drin. Sofern möglich sollte man Header aber immer erst im .cpp inkludieren, wie bereits gesagt wurde. das klingt nach einer guten idee werde ich mir noch genauer anschauen.
Bearbeitet von wergor am 17.10.2014, 17:01
|