[gelöst] Problem mit Funktionszeiger
-
Hallo,
folgendes würde ich gerne umsetzen, doch leider bekomme ich die Sache mit den Funktionszeigern nicht in den Griff.
Ich habe 2 Klassen, Klasse1 und Klasse2.
In Klasse1 erzeuge ich ein Objekt von Klasse2. Ich möchte nun einer Funktion in in Klasse2, welche Klasse1 ja nicht kennt, einen Funktionszeiger einer Funktion aus Klasse1 übergeben, welche die Klasse2 bei Eintreten eines bestimmten Ereignisses aufruft.
Ist so etwas überhaupt umzusetzen?
z.B. (Code ungetestet - nur ein Beispiel)
#include "Klasse2.h" class Klasse1 { public: Klasse1(); void incommingData(){ //foobar z.B. Ausgaben }; // Die Funktion evtl. Private?? private: Klasse2 kl2; }; Klasse1::Klasse1() { kl2.sindDieDatenDa(incommingData); }class Klasse2 { public: sindDieDatenDa(void callBack()) { // .... if(irgendwas) // irgendein Event ist eingetreten. Daten am COM-Port empfangen { callBack(); }; } };Danke schon mal für eure Hilfe!!!!
-
Das geht grunsätzlich. Allerdings funktionieren Member Funktionszeiger nicht so trivial, wie normale Funktionszeiger. Zusätzlich brauchst du noch ein Objekt, auf welches du diesen anwenden kannst.
Dazu findet man aber hier im Forum, sowie bei google recht viel.
-
Hallo drakon,
danke für deine fixe Antwort. Habe gestern noch mal ein bißchen deinen Link angeschaut, Tante Google befragt und auch ein entsprechendes Beispiel gefunden und mir daraus in etwa folgendes gebaut:
#include <iostream> class B; typedef int (B::*funptr) (int); class A { private: funptr ptr; public: void callFunction(funptr p, B* obj) { ptr = p; (*obj.*ptr)(); } }; class B { public: int callHallo() { std::cout << "Hallo Welt!\n"; } void run() { A* obj = new A; obj->callFunction(&B::callHallo(), this); } }; int main() { B* obj = new B; obj->run(); }Quelle: http://www.informatik-forum.at/showthread.php?t=15545
Da irgendwas nicht funktioniert hat (Programmabsturz beim Funktionsaufruf via Funktionszeiger), habe ich mal ein paar Ausgaben eingebaut. Der This-Pointer welcher an die Funktion "callFunction()" der Klasse A übergeben wird ist dort 0 und verursacht deshalb wohl den Absturz. Kanns mir irgendwie nicht erklären!?!?
Weißt du Rat?
Danke und sonnige Grüße
-
Stonecold_Mario schrieb:
Da irgendwas nicht funktioniert hat (Programmabsturz beim Funktionsaufruf via Funktionszeiger), habe ich mal ein paar Ausgaben eingebaut.
Du meinst, du konntest diesen Code kompilieren? Du musst einen sehr nachlässigen Compiler haben. Da sind drei Fehler drin:
- funptr passt nicht auf callHallo, weil die Parameter nicht übereinstimmen.
- In callHallo fehlt eine return-Anweisung
- Wenn du callHallo als Methodenzeiger übergibst, darfst du dahinter keine Klammern setzen.
-
Hallo MFK,
danke für deine Antwort. Nein du hast recht, das hätte mein Kompiler natürlich auch nicht gebaut. Ich habe den Code aus der Quelle genommen und versucht ihn so anzupassen, dass er in etwa dem meinigen gleicht. Kompiliert habe ich ihn natürlich nicht. Hier mal ein kleine Korrektur:
#include <iostream> class B; typedef void (B::*funptr) (void); class A { private: funptr ptr; public: void callFunction(funptr p, B* obj) { ptr = p; (*obj.*ptr)(); } }; class B { public: void callHallo() { std::cout << "Hallo Welt!\n"; } void run() { A* obj = new A; obj->callFunction(&B::callHallo, this); } }; int main() { B* obj = new B; obj->run(); }So ist es vielleicht besser. Kann es leider gerade nicht kompilieren. Solltest du also noch einen Fehler finden kannst du ihn ja vielleicht selber eben fixen.
So nun aber zu meinem Problem, dass immer noch nicht gelöst ist. Weißt du Rat?
Gruß,
Mario
-
Stonecold_Mario schrieb:
So nun aber zu meinem Problem, dass immer noch nicht gelöst ist. Weißt du Rat?
Nein. Der gezeigte Code funktioniert. Wenn du "angepassten" oder "Beispiel"-Code zeigst, solltest du sicherstellen, dass dieser Code auch das Fehlverhalten reproduziert. Ansonsten bringt das gar nichts.
So kann man nur vermuten, dass du im echten Code etwas falsch machst, diesen Fehler aber nicht in deine Beispiele überträgst.
-
Okay danke dir. Werde nachher nochmal den Beispielcode und auch meinen eigenen testen und mich dann wieder melden. Evtl. versuche ich mal meinen den betreffenden Teil meines Codes zu posten.
Gruß,
Mario
-
Hallo MFK,
ich habe den Beispielcode von heute morgen mal probiert und dieser läuft bei mir auch. Sorry hatte gehofft, dass er den selben Fehler produziert. Mein Fehler ist aber immer noch da und ich weiß nicht so recht warum. Bin gerade dabei eine Lib für die Kommunikation mit ner Seriellen Schnittstelle zu bauen. Ich weiß, vergleichbares gibt es im Netz aber gerne auch verstehen was ich benutze und deshalb versuche ich es halt selber mal. Im Grunde funktioniert auch alles so weit nur die Sache mit dem Funktionszeiger nicht. Würde dir gerne das kleine Projekt mal zukommen lassen doch leider kann ich dem Beitrag scheinbar nicht anhängen.
Soll ich den kompletten Code hier posten?
Gruß,
Mario
-
versuche den code soweit wie möglich zu kürzen, so dass der fehler aber trotzdem noch auftritt.
ach, und poste zuallererst mal die fehlermeldung, die dir dein compiler ausgibt.
-
Okay hier mal der Code. BasisThread ist wie der Name schon sagt eine Basisklasse für einen Win32-Thread.
ReceiverThread.h
#ifndef RECEIVERTHREAD_H #define RECEIVERTHREAD_H #include <windows.h> #include "BasisThread.h" class SerialCommunicator; typedef void (SerialCommunicator::*funptr) (void); class ReceiverThread : public BasisThread { public: ReceiverThread(); ~ReceiverThread(); void setData(HANDLE* inHandle, OVERLAPPED* inReadOverlapped, funptr p, SerialCommunicator* obj); protected: virtual int run(void); private: HANDLE* h_comm; OVERLAPPED* m_readOverlapped; //void callBack(); funptr ptr; }; #endif // RECEIVERTHREAD_HReceiverThread.cpp
#include "ReceiverThread.h" #include <iostream> ReceiverThread::ReceiverThread() : BasisThread() { } ReceiverThread::~ReceiverThread() { } void ReceiverThread::setData(HANDLE* inHandle, OVERLAPPED* inReadOverlapped, funptr p, SerialCommunicator* obj) { ptr = p; std::cout << "ReceiverThread::setData(): obj = " << obj << " fun = " << p << std::endl; (*obj.*ptr)(); THREAD_SAFE_ACCESS { h_comm = inHandle; m_readOverlapped = inReadOverlapped; } END_THREAD_ACCESS } int ReceiverThread::run(void) { while(1) { // Aufgabenerfüllung } }SerialCommunication.h
#ifndef SERIALCOMMUNICATION_H #define SERIALCOMMUNICATION_H #include <windows.h> static const unsigned int RECEIVEBUFFER_LENGTH = 256; static const unsigned int COMPORT_LENGTH = 8; static const unsigned int PREFIX_LENGTH = 8; // forward declaration class ReceiverThread; class Publisher { public: virtual void dataReceived() = 0; // callback if data received on COM-Port }; class SerialCommunicator { public: static enum sc_parity { sc_parity_evenparity = 0, sc_parity_markparity, sc_parity_noparity, sc_parity_oddparity, sc_parity_spaceparity }; static enum sc_stopbits { sc_stopbits_onestopbit = 0, sc_stopbits_one5stopbit, sc_stopbits_twostopbit }; SerialCommunicator(Publisher* pubObj); ~SerialCommunicator(); HANDLE openCommunication(const char* port); BOOL setDCB( HANDLE handle, const int baudrate = 9600, const int bytesize = 8, sc_parity parity = sc_parity_noparity, sc_stopbits stopbits = sc_stopbits_onestopbit); BOOL setTimeOuts( unsigned int readIntervalTimeOut = 100, unsigned int readTotalTimeoutMultiplier = 0, unsigned int readTotalTimeoutConstant = 1, unsigned int writeTotalTimeoutMultiplier = 0, unsigned int writeTotalTimeoutConstant = 0 ); int sendData( bool& isWritten, const char* msg = NULL, bool withPrefix = false); char* receiveData( int& noOfReceivedBytes, BOOL& isRead); const char* getComPort(); BOOL closeCommunication(HANDLE handle); void incommingData(); private: HANDLE h_comm; DCB m_dcb; COMMTIMEOUTS m_timeOuts; ReceiverThread* t_receiverThread; OVERLAPPED m_readOverlapped; OVERLAPPED m_writeOverlapped; char m_comPort[COMPORT_LENGTH]; char m_progPrefix[PREFIX_LENGTH]; Publisher* p_publisherObject; char m_receiveBuffer[RECEIVEBUFFER_LENGTH]; }; #endif //SERIALCOMMUNICATION_HSerialCommunication.cpp
#include "SerialCommunication.h" #include <iostream> #include <sstream> #include "ReceiverThread.h" SerialCommunicator::SerialCommunicator(Publisher* pubObj) //: p_publisherObject(pubObj) { p_publisherObject = static_cast<Publisher*>(pubObj); memset(&m_dcb, 0, sizeof(m_dcb)); memset(&m_timeOuts, 0, sizeof(m_timeOuts)); memset(m_comPort, '\0', COMPORT_LENGTH); memset(&m_readOverlapped, 0 ,sizeof(m_readOverlapped)); memset(&m_writeOverlapped, 0 ,sizeof(m_writeOverlapped)); m_readOverlapped.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); m_writeOverlapped.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); h_comm = INVALID_HANDLE_VALUE; // Initialisierung des Handle t_receiverThread = new ReceiverThread(); m_progPrefix[0] = char(0xE6); m_progPrefix[1] = char(0xB5); m_progPrefix[2] = char(0xBA); m_progPrefix[3] = char(0xB9); m_progPrefix[4] = char(0xB2); m_progPrefix[5] = char(0xB3); m_progPrefix[6] = char(0xA9); m_progPrefix[7] = '\0'; } SerialCommunicator::~SerialCommunicator() { closeCommunication(h_comm); delete t_receiverThread; } HANDLE SerialCommunicator::openCommunication(const char* port) { closeCommunication(h_comm); strncpy_s(m_comPort, COMPORT_LENGTH -1, port, COMPORT_LENGTH -1); h_comm = CreateFile( m_comPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, // 0, ++++++++ WAS MACHT DAS FILE_FLAG_OVERLAPPED 0); if (h_comm == INVALID_HANDLE_VALUE) { //int error = GetLastError(); CloseHandle(h_comm); return NULL; } else { t_receiverThread->setData(&h_comm, &m_readOverlapped, &SerialCommunicator::incommingData, this); std::cout << "SerialCommunicator::openCommunication(): obj = " << this << " fun = " << &SerialCommunicator::incommingData << std::endl; t_receiverThread->startThread(); return h_comm; } } int SerialCommunicator::sendData(bool& isWritten, const char* msg, bool withPrefix) { std::ostringstream sstr; if(withPrefix) { sstr << m_progPrefix << msg; /*std::cout << sstr.str().c_str() << " --- " << m_progPrefix << " --- " << msg << std::endl;*/ } else { sstr << msg; } DWORD numberOfBytesWritten; if(WriteFile(h_comm, sstr.str().c_str(), sstr.str().length(), &numberOfBytesWritten, &m_writeOverlapped)) { isWritten = true; } else { if(ERROR_IO_PENDING == GetLastError()) { if( WAIT_OBJECT_0 == WaitForSingleObject( m_writeOverlapped.hEvent, 200 ) ) { isWritten = true; } else { isWritten = false; } } else { isWritten = false; } } return numberOfBytesWritten; } char* SerialCommunicator::receiveData(int& noOfReceivedBytes, BOOL& isRead) { memset(m_receiveBuffer, '\0', RECEIVEBUFFER_LENGTH); DWORD NumberOfBytesRead; if(ReadFile(h_comm, m_receiveBuffer, RECEIVEBUFFER_LENGTH-1, &NumberOfBytesRead, &m_readOverlapped)) { isRead = true; } else { if(ERROR_IO_PENDING == GetLastError()) { if( WAIT_OBJECT_0 == WaitForSingleObject( m_readOverlapped.hEvent, 200 ) ) { isRead = true; } else { isRead = false; } } else { isRead = false; } } noOfReceivedBytes = NumberOfBytesRead; return m_receiveBuffer; } BOOL SerialCommunicator::setDCB(HANDLE hCom, const int baudrate, const int bytesize, sc_parity parity, sc_stopbits stopbits) { //BOOL fSuccess = GetCommState(h_comm, &m_dcb); m_dcb.BaudRate = baudrate; m_dcb.ByteSize = bytesize; switch(parity) { case sc_parity_evenparity: m_dcb.Parity = EVENPARITY; break; case sc_parity_markparity: m_dcb.Parity = MARKPARITY; break; case sc_parity_noparity: m_dcb.Parity = NOPARITY; break; case sc_parity_oddparity: m_dcb.Parity = ODDPARITY; break; case sc_parity_spaceparity: m_dcb.Parity = SPACEPARITY; break; default: m_dcb.Parity = NOPARITY; break; } switch(stopbits) { case sc_stopbits_onestopbit: m_dcb.StopBits = ONESTOPBIT; break; case sc_stopbits_one5stopbit: m_dcb.StopBits = ONE5STOPBITS; break; case sc_stopbits_twostopbit: m_dcb.StopBits = TWOSTOPBITS; break; default: m_dcb.StopBits = ONESTOPBIT; break; } return SetCommState(h_comm, &m_dcb); } BOOL SerialCommunicator::setTimeOuts( unsigned int readIntervalTimeOut, unsigned int readTotalTimeoutMultiplier, unsigned int readTotalTimeoutConstant, unsigned int writeTotalTimeoutMultiplier, unsigned int writeTotalTimeoutConstant ) { m_timeOuts.ReadIntervalTimeout = readIntervalTimeOut; m_timeOuts.ReadTotalTimeoutMultiplier = readTotalTimeoutMultiplier; m_timeOuts.ReadTotalTimeoutConstant = readTotalTimeoutConstant; m_timeOuts.WriteTotalTimeoutMultiplier = writeTotalTimeoutMultiplier; m_timeOuts.WriteTotalTimeoutConstant = writeTotalTimeoutConstant; return SetCommTimeouts(h_comm,&m_timeOuts); } const char* SerialCommunicator::getComPort() { return m_comPort; } BOOL SerialCommunicator::closeCommunication(HANDLE handle) { t_receiverThread->killThread(); BOOL retVal = true; //if(handle != INVALID_HANDLE_VALUE) //{ retVal = CloseHandle(handle); handle = INVALID_HANDLE_VALUE; //} return retVal; } void SerialCommunicator::incommingData() { std::cout << "############################\n"; p_publisherObject->dataReceived(); }Ich habe versucht nur das Notwendigste zu posten. Kann sein dass irgendwo noch ne Klammer fehlt oder so. Das VS2005 Projekt kann ich per Mail verschicken.
Das Problem findet sich in ReceiverThread::setData(...);
Danke für die Hilfe!
-
queer_boy schrieb:
versuche den code soweit wie möglich zu kürzen, so dass der fehler aber trotzdem noch auftritt.
ach, und poste zuallererst mal die fehlermeldung, die dir dein compiler ausgibt.340 Zeilen sind nicht sehr gekürzt..
-
Der Kompiler gibt keine Fehlermeldung aus. Alles lässt sich wunderbar bauen.
Wenn ich in in der setData-Funktion von ReceiverThread bin, ist der übergebene this-Pointer (hier *obj) gleich 0.
-
Stonecold_Mario schrieb:
Der Kompiler gibt keine Fehlermeldung aus. Alles lässt sich wunderbar bauen.
Wenn ich in in der setData-Funktion von ReceiverThread bin, ist der übergebene this-Pointer (hier *obj) gleich 0.
Na dann schau mal, wieso der 0 ist. (Dann musst du aber zum Aufrufer von setData gehen.
Also hier:
SerialCommunicator::openCommunication
-
Sicher, nur sehe ich nicht warum this nun 0 ist.
t_receiverThread->setData(&h_comm, &m_readOverlapped, &SerialCommunicator::incommingData, this); std::cout << "SerialCommunicator::openCommunication(): obj = " << this << " fun = " << &SerialCommunicator::incommingData << std::endl;Die Ausgabe zeigt ja eine Objektadresse != 0
-
Wenn du da mit dem Debuger Schrit für Schritt dann in die Funktion reingehst, und vorher die Adresse nicht 0 hast und beim nächsten Schritt ist in der Funktion 0? - Kann ich mir nur schwer vorstellen.
-
Nur mal die Sachen die aufgefallen sind.
Funktionsaufruf:
this 0x009f5110 {h_comm=0x00000ee4 m_dcb={...} m_timeOuts={...} ...} SerialCommunicator * const
h_comm 0x00000ee4 void *
t_receiverThread 0x009f4d68 {h_comm=0xcdcdcdcd m_readOverlapped=0xcdcdcdcd ptr=0xcdcdcdcd } ReceiverThread *
p_publisherObject 0x009938dc {serialCom=0x009f5110 hCom=0xffffffff } Publisher *
Nächster Schritt:
obj 0x00000000 {h_comm=??? m_dcb={...} m_timeOuts={...} ...} SerialCommunicator *h_comm CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
t_receiverThread CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
p_publisherObject CXX0017: Fehler: Symbol "" nicht gefunden
Ich erkenne ein Problem. Weiß aber nicht warum es da ist.
-
Sind bezüglich der Meldungen im Debugger nur keine vernünftigen Debuginfos für die Lib erstellt worden? Wo kann ich das im VC2005 für die statische Lib einstellen (/DEBUG)? Linkereinstellungen gibt es für die Lib ja nicht?
-
Okay ich habe hier nochmal das Beispiel von heute morgen so gebaut, dass ebenfalls der selbe Fehler auftritt. Ist jetzt vielleicht einfacher nachzuvollziehen. Ich werde nicht schlau.
A.h
#ifndef A_H #define A_H class B; typedef void (B::*funptr) (void); class A { private: funptr ptr; public: void callFunction(funptr p, B* obj); }; #endif // A_HA.cpp
#include "A.h" void A::callFunction(funptr p, B* obj) { ptr = p; (*obj.*ptr)(); }B.h
#ifndef B_H #define B_H class B { public: void callHallo(); void run(); }; #endif // B_HB.cpp
#include "B.h" #include <iostream> #include "A.h" void B::callHallo() { std::cout << "Hallo Welt!\n"; } void B::run() { A* obj = new A; obj->callFunction(&B::callHallo, this); }main.cpp
#include "B.h" int main() { B* obj = new B; obj->run(); }Es scheint problematisch zu sein, wenn die Funktion callFunction der Klassen A in einer seperaten cpp-Datei implementiert wird.

Schönen Abend noch!!!
-
#include "A.h" //zuerst #include "B.h" #include <iostream> void B::callHallo() { std::cout << "Hallo Welt!\n"; } void B::run() { A* obj = new A; obj->callFunction(&B::callHallo, this); }
-
Wow danke,
genau das war das Problem. Jetzt funktioniert es auch bei meinen Prog.
Da wäre ich so schnell nicht drauf gekommen, wenn überhaupt.Was genau ist jetzt das Problem gewesen. Warum ist es wichtig die Reihenfolge der Includes zu beachten?
Nochmal danke und Gruß,
Mario
-
Stonecold_Mario schrieb:
Warum ist es wichtig die Reihenfolge der Includes zu beachten?
Ist es eigentlich nicht. Du könntest ein Problem mit einer nicht standardgemäßen Optimierung deines Compilers haben (etwa Visual C++: benutz zur Sicherheit den Schalter /vmg). Das Problem würde dann auch nicht auftreten, wenn du Zeiger auf Member nie deklarierst, bevor die betreffende Klasse definiert wurde (was meistens möglich ist; hier: vor der Klassendefinition von A den Header für B einbinden).