C++ method pointer?

Mar 09, 2016 24 Replies

Problem: eine Klasse implementiert mehrere (gleichartige) Methoden, von denen eine bestimmte zur Laufzeit aufgerufen werden soll. Leider sind meine C++ Kenntnisse sehr angestaubt, ich komme nicht drauf wie sich das


Ewas konkreter: Es geht um die Klasse IRrecv aus der Arduino IRremote


innerhalb seiner Klasse erzeugen, vorbesetzen und dann aufrufen. Sowas wie:



In der Bibliothek:



class IRrecv { public: bool decodeNEC(); bool decodeSony(); ... bool() *Decoder; //??? soll auf eine der o.g. Methoden zeigen



initialisieren char read(); //soll intern Decoder aufrufen };



IRecv::read() { if (*Decoder()) //??? soll die Methode aufrufen return results.asc; else return '?'; }



Im Programm:



IRrecv irrecv(IR_PIN); //erzeugt Instanz (Singleton)



void setup() { irrecv.begin(&decodeNEC); //??? soll den Pointer initialisieren }



void loop() { if (irrecv.available()) { char data = irrecv.read(); ... } }



Da die Methode nur innerhalb der (selben) Instanz aufgerufen werden


TIA DoDi


Hans-Peter Diettrich schrieb:

Dekoder dann in davon erbenden Klassen zu implementieren.

  1. Christian

Christian Zietz - CHZ-Soft - czietz (at) gmx.net WWW: http://www.chzsoft.de/ PGP/GnuPG-Key-ID: 0x52CB97F66DA025CA / 0x6DA025CA

Christian Zietz schrieb:

Sowas dachte ich mir schon ;-)

Verweis auf die Arduino Bibliothek.

Bibliothek auf. Das riecht dann irgendwie nach einem Template?

direkt aufrufen.

Da war ich schon, hilft mir aber nicht bei allen Details :-(

DoDi

Am 09.03.2016 um 18:14 schrieb Hans-Peter Diettrich:

Um Memberfunktionen aufzurufen brauchst Du den Zeiger auf das Objekt.

Wieviel verschiedene Dekoder gibt es denn? Entweder Du baust Dir ein Interface, und erzeugst Dir passende Objekte je nachdem was Du brauchst, oder Du erledigst das einfach mit ner if-Abfrage, oder mit einem switch case Block.

begin(IRecv::DecodeNEC);

IRecv::read() { if (decoder==DecoderNEC) return decodeNEC; else return decodeSony(); }

Christian Zietz schrieb:

In den vorhandenen Bibliotheken gibt es eine universelle decode()

virtuellen Methoden nicht funktionieren. Die habe ich dann schon mal in

einer unbekannten Fernbedienung) weiterhin verwendet werden kann. Das

Speicher) soll unbedingt wegfallen, wenn man nur von einer bestimmten

Hinweis dankbar :-)

DoDi

Hans-Peter Diettrich schrieb:

Im Quellcode vielleicht. Compiliert kommt ziemlich genau das heraus, was

abgeleitete Klasse hat eine vtable mit einem Pointer auf ihre decode-Methode.

AbstractDecoder* decoder = AbstractDecoder::createDecoder(x); decodeddata = decoder->decode(data);

Je nach Wert von 'x' wird 'decoder' nun zur Laufzeit eine Instanz von SonyDecoder, NECDecoder usw. Trotzdem ruft decoder.decode() immer die passende decode-Methode (und nicht etwa die in AbstractDecoder) auf.

hintippen, aber in d.s.e ist das doch arg off-topic.

Christian

Christian Zietz - CHZ-Soft - czietz (at) gmx.net WWW: http://www.chzsoft.de/ PGP/GnuPG-Key-ID: 0x52CB97F66DA025CA / 0x6DA025CA

Deshalb wollte ich ja die Methode innerhalb des Objekts aufrufen, dann ist die Instanz ja bereits bekannt (this).

haben noch viel weniger Ahnung von C++ als ich ;-)

nicht (mehr) aus :-(

DoDi

Christian Zietz schrieb:

(siehe andere Mail).

verzichten, ich hatte auch schon an einen Aufruf wie

gedacht. Aber leider liegen manche Parameter in der Instanz der Klasse,

Bibliotheken beibehalten.

ja unbedingt C oder C++ sein :-(

Zugegeben, in dieser Gruppe findet sich bereits mehr off-topic als

DoDi

Am 09.03.2016 um 20:11 schrieb Hans-Peter Diettrich:

Dann ein Interface, bzw. abstrakte Klasse, da es in C++ keine Interfaces gibt, und dann das passende Objekt erzeugen. Hat Christian bereits geschrieben.

Nein, dazu braucht man keine Templates.

Oder willst Du vor dem Kompilieren entscheiden welcher Dekoder benutzt wird?

MfG

Hans-Peter Diettrich schrieb:

Den Grund habe ich allerdings nicht verstanden. Auf alle Decoder zugreifen kannst Du mit virtuellen Methoden doch ebenso. Aber egal, dann

Dann halt als Makro, wobei eine Basisklasse und virtuelle Methoden

verwendete Decoder aussortieren.

#define GET_DECODER(x) (new x##Decoder)

AbstractDecoder* decoder = GET_DECODER(Sony); decoder->decode(data);

Christian

Christian Zietz - CHZ-Soft - czietz (at) gmx.net WWW: http://www.chzsoft.de/ PGP/GnuPG-Key-ID: 0x52CB97F66DA025CA / 0x6DA025CA

Hans-Peter Diettrich schrieb:

Nur mal eine allgemeine Anmerkung:

Pascal. VMT, abstrakte und virtuelle Methoden, Klassendeklarationen,

Marc

Rot ist negativ, blau ist positiv.

Ja, den Rest gibt es ja schon.

DoDi

Marc Santhoff schrieb:

DoDi

Hans-Peter Diettrich schrieb:

In der schon geposteten FAQ beschrieben.

Christian

-- Christian Zietz - CHZ-Soft - czietz (at) gmx.net WWW:

formatting link
PGP/GnuPG-Key-ID: 0x52CB97F66DA025CA / 0x6DA025CA

Hans-Peter Diettrich schrieb:

Zu Pointer und Funktionen:

formatting link

formatting link

Mein PDF hatte zwar eine total verfusselte Seitennummerierung, war aber

Marc

Am 09.03.2016 um 22:31 schrieb Hans-Peter Diettrich:

eher verwirrt.

MfG

Ein Singleton kann eigentlich komplett statisch sein, so dass Du die einfacheren C-Funktionspointer verwenden kannst, indem Du die Methoden

class IRrecv;

typedef bool (foo_decode)(IRrecv* pThis);

class IRrecv { public: static bool decodeNEC(IRrecv* pThis); static bool decodeSony(IRrecv* pThis); char read(foo_decode pFoo); //soll intern Decoder aufrufen };

char IRrecv::read(foo_decode pFoo) { if (pFoo(this)) //??? soll die Methode aufrufen return 'r'; else return '?'; }

int main() { IRrecv irrecv; irrecv.read(IRrecv::decodeNEC);

dem sich die Funktionen als Objekt handhaben lassen:

struct i_decode { // Definition des Interface virtual ~i_decode() {} // verhindert Compilerwarnung virtual bool decode()= 0; // Deklaration Funktionsaufruf };

struct f_decode_NEC: public i_decode { // Definition eines Dekoders, beachte Vererbung vom Interface virtual ~f_decode_NEC() {} // verhindert Compilerwarnung virtual bool decode() { return true; } // Definition Funktion };

struct f_decode_Ed: public i_decode { // Definition noch eines Dekoders virtual ~f_decode_Ed() {} // verhindert Compilerwarnung virtual bool decode() { return false; } };

i_decode* pFoo= new f_decode_NEC; // Funktionsobjekt anlegen if (pFoo->decode()) do_anything(); // benutzt decode_NEC

oder statisch:

f_decode_NEC DNC; // Funktionsobjekt anlegen i_decode* pFoo= &DNC; // Dem Zeiger zuweisen

Moin,

Hans-Peter Diettrich schrieb:

Ich hab das mal so geschrieben, wie Du es vermutlich haben willst,

//------------------------- class IRrecv { public: bool decodeNEC(); bool decodeSony(); //... bool (IRrecv::*Decoder)() ; // Member Function Pointer

void begin( bool (IRrecv::*which)() ); char read(); //soll intern Decoder aufrufen };

char IRrecv::read() { if ( (this->*Decoder)() ) // soll die Methode aufrufen return '!'; else return '?'; }

IRrecv irrecv; //erzeugt Instanz (Singleton)

void setup() { //MemFunc Pointer initialisieren irrecv.begin( &IRrecv::decodeNEC ); }

Konstrukte in C++ auch, z.B. templates.

- Heinz

dann noch die Klasse selbst. Das Ergebnis habe ich momentan bereits in

auch die Elemente der Klasse enthalten. [...]

sollte ich wohl noch Makros definieren.

Beibehaltung der Klasse entschieden, mit den Standard-Methoden begin(), available() und read(), die jeder Arduino Programmierer von den anderen Stream-Klassen gewohnt ist.

Speicherbedarf (zumindest bei den VMT).

DoDi

Heinz Saathoff schrieb:

[...] Danke, das ist genau die Antwort, die ich erwartet habe :-)

Jetzt komme ich wohl nicht umhin, Dich im Header der Bibliothek als

DoDi

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required