Zum Inhalt springen

Callback von außerhalb in eine Klasse


Janosh

Empfohlene Beiträge

Hi Forum,

nach einer stundenlangen Suche nach einer Lösung gebe ich auf und frage lieber einmal nach, bevor mir noch mehr Zeit verloren geht.

Ich habe folgende Situation:

1) MFC dialogbasierte Anwendung

2) die zugehörige Klasse des Dialogs CDialogDlg

3) ein vollständig gekapsteltes Objekt ohne Verbindung zur Klasse CDialogDlg

4) Dialog in C++, Objekt in C geschrieben

5) MS Visual Studio 2005

Ich habe ein vollständiges Error-Handling in dem Objekt implementiert und möchte nun die Errorcodes extrahieren und in ein Logfile schreiben.

Da ich aber die gesamte File-Verwaltung in meinem Dialog belassen möchte, wollte ich dem Objekt einen Funktions-Pointer auf eine Member-Funktion der Dialogklasse übergeben. Dann hätte das Objekt über den Pointer direkt die Memberfunktion von CDialogDlg aufgerufen und die Message würde gelogged werden.

Mein großes Problem besteht nun darin, dass das Objekt nichts von meiner Klasse wissen darf, damit ich das Objekt flexibel in allen möglichen Umgebungen benutzen kann, auch mal unter einer direkten C-Konsolen-Applikation.

Ist es irgendwie möglich, dass die Klasse dem Objekt einen wie auch immer gearteten Zugang zu ihrer Memberfunktion "void WriteLog (char*)" gibt?

Ich habe zwar schon viele Lösungen gefunden, aber immer war Voraussetzung, dass die beiden Partner sich gegenseitig kannten.

Sollte es nicht gehen, wäre ich auch für Vorschläge offen, wie ich mein Problem lösen könnte.

Ich hoffe, ihr könnt mir helfen. Danke schonmal an alle, die sich die Zeit nehmen.

Viele Grüße,

Janosh

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi,

also ich sehe, ich habe es noch nicht gut genug erklärt. Sorry dafür.

Zustand:

Ich habe eine Klasse, in der ich eine Memberfunktion habe, die übergebene char* in eine Datei schreibt. Also ganz simpler Aufbau:

class CDialogDlg

{

public:

CDialogDlg ();

~CDialogDlg();

void WriteString (char*);

}

Desweiteren habe ich jetzt von einem Kollegen ein gekapseltes Objekt bekommen, das komplett in C programmiert wurde und auf keinen Fall eine Instanz der Klasse bekommen darf (da es ja sonst nicht mehr vollständig gekapselt wäre).

Das Objekt ist eine Sammlung von C-Funktionen, die aber auch Meldungen wegschreiben können sollen, und zwar direkt zu dem Zeitpunkt, wenn sie auftreten. Es bringt also nichts, alle Meldungen in einem Array zu sammeln und nach der Rückkehr in die Klasse erst alles zu schreiben.

Mein Ansatz war nun, dass mein Kollege einen einfachen 'void (*WriteMsg)(char*)' Funktionspointer in seinem Objekt einbaut, den ich aus der Klasse mit der Adresse meiner WriteString-Funktion füttere. Anschließend kann er immer - falls der Funktionspointer nicht NULL ist - darauf zugreifen und seine Nachrichten loggen.

Mein Problem dabei war jetzt allerdings, dass mir der Compiler gesagt hat, dass ich von außerhalb der Klasse nicht auf ein Klassenmember zugreifen kann, ohne die Klasse bekannt zu machen.

Daraufhin hab ich es mit einer statischen Memberfunktion versucht, was daran scheiterte, dass ich dann nicht mehr auf den File-Pointer zugreifen kann, bzw. die Zeitinformation (des Programmstarts), die im Dateinamen enthalten ist.

Eine weitere Möglichkeit wäre jetzt, dass ich den Dateinamen nicht dynamisch vergebe, sondern einen festen Namen benutze. Dann könnte ich aber auch nur noch 1 Logfile benutzen und nicht mehr zwischen den einzelnen Programmaufrufen unterscheiden.

Und daraus ergeben sich nunmal meine Anforderungen, die mir so Kopfzerbrechen bereiten:

- Das Objekt (die c und h Datei meines Kollegen) darf keine Instanz oder Deklaration der Klasse bekommen, um die Kapselung nicht zu verlieren.

- Der Dateiname für die Log-Datei muss sich bei Programmstart generieren und muss ab dem Moment verwendet werden.

Ich hoffe, mein Problem ist jetzt ein wenig klarer geworden. Und nein, ich benutze kein .NET, sondern reines VC++.

Danke schonmal im Voraus.

Gruß,

Janosh

Link zu diesem Kommentar
Auf anderen Seiten teilen

Desweiteren habe ich jetzt von einem Kollegen ein gekapseltes Objekt bekommen, das komplett in C programmiert wurde und auf keinen Fall eine Instanz der Klasse bekommen darf (da es ja sonst nicht mehr vollständig gekapselt wäre).

Da du ja in der einen Klasse deine Logger Klasse verwenden willst macht der Gedankengang nicht viel Sinn.

Mein Ansatz war nun, dass mein Kollege einen einfachen 'void (*WriteMsg)(char*)' Funktionspointer in seinem Objekt einbaut, den ich aus der Klasse mit der Adresse meiner WriteString-Funktion füttere. Anschließend kann er immer - falls der Funktionspointer nicht NULL ist - darauf zugreifen und seine Nachrichten loggen.

Das funktioniert wie bereits gesagt und du ja auch schon festgestellt hast nur mit statischen Methoden

Daraufhin hab ich es mit einer statischen Memberfunktion versucht, was daran scheiterte, dass ich dann nicht mehr auf den File-Pointer zugreifen kann, bzw. die Zeitinformation (des Programmstarts), die im Dateinamen enthalten ist.

Das liegt aber dann nur an deinem Klassendesign und nicht an irgendeiner Begrentzung alla "In statischen Methoden kann man nicht auf den File Pointer zugreifen" ;)

Du kannst in einer statischen Klassenmethode natürlich nur auf andere Member dieser Klasse zugreifen wenn diese auch statisch sind oder indem du eine Instanz deiner Klasse anlegst.

- Das Objekt (die c und h Datei meines Kollegen) darf keine Instanz oder Deklaration der Klasse bekommen, um die Kapselung nicht zu verlieren.

das macht wie bereits gesagt nicht viel Sinn bzw. würde das nur Sinn ergeben wenn du deine Logger Klasse später evtl. durch eine andere austauschen wollen würdest. In dem Fall würde man ein Interface verwenden.

- Der Dateiname für die Log-Datei muss sich bei Programmstart generieren und muss ab dem Moment verwendet werden.

Das ist unabhängig von den hier beschriebenen Problemen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Daraufhin hab ich es mit einer statischen Memberfunktion versucht, was daran scheiterte, dass ich dann nicht mehr auf den File-Pointer zugreifen kann, bzw. die Zeitinformation (des Programmstarts), die im Dateinamen enthalten ist.
Wieviele Instanzen deiner Klasse existieren denn gleichzeitig? Spricht etwas dagegen, einen statischen Instanzzeiger zu benutzen, über den du dann in der statischen Methode an die Instanz herankommst?

- Das Objekt (die c und h Datei meines Kollegen) darf keine Instanz oder Deklaration der Klasse bekommen, um die Kapselung nicht zu verlieren.

Wenn dieses "Objekt" in C geschrieben ist, kann es mit einer C++-Klassendefinition sowieso nichts anfangen.
Link zu diesem Kommentar
Auf anderen Seiten teilen

Da du ja in der einen Klasse deine Logger Klasse verwenden willst macht der Gedankengang nicht viel Sinn.

Der Gedankengang an sich macht schon Sinn.

Meine "Logger-Klasse" ist mein Dialog, in den alles eingebettet wird. Die Logger-Funktion, die Teil der Dialogklasse ist, besteht momentan nur aus einem fprintf, in dem der input-string an den filepointer (Klassenmember) übergeben wird. Meine Dialogimplementierung ist ja nur die momentane Verwendung dieses Objekts meines Kollegen. Wenn wir es später nochmal verwenden, kann es sein, dass wir z.B. eine vollständige C-Umgebung für eine Konsolen-Applikation verwenden.

Der Sinn des gesamten Konzepts liegt darin, dass sich das Objekt nicht ändert, sondern nur der Funktionszeiger auf die Write-Funktion im "main". Mein bisheriger Ansatz hierfür war eben nur der, über einen Funktionszeiger zu gehen, was aber grad beim Zugriff auf eine Klasse Probleme macht.

Das liegt aber dann nur an deinem Klassendesign und nicht an irgendeiner Begrentzung alla "In statischen Methoden kann man nicht auf den File Pointer zugreifen" ;)

Du kannst in einer statischen Klassenmethode natürlich nur auf andere Member dieser Klasse zugreifen wenn diese auch statisch sind oder indem du eine Instanz deiner Klasse anlegst.

Das ist schon klar, aber dann hab ich ja eine neue Instanz der Klasse, wo die Membervariablen einen anderen Wert (konkret keinen initialisierten Filepointer) haben.

das macht wie bereits gesagt nicht viel Sinn bzw. würde das nur Sinn ergeben wenn du deine Logger Klasse später evtl. durch eine andere austauschen wollen würdest. In dem Fall würde man ein Interface verwenden.

Es ist zwar keine Klasse, auf die ich zugreifen will, sondern wie gesagt nur eine Funktion mit einem fprintf drin, aber der Sinn ist, dass man später einfach nur an dieser einen Stelle abändert, wo und wie die Informationen weiterverarbeitet werden.

Natürlich wäre es kein Problem, diese Logging-Tasks in jedem Programm-Teil unabhängig voneinander zu lösen. Ich will aber erreichen, dass ich ein "Objekt" oder um es verständlicher zu betiteln eine "Funktionssammlung" einmal schreibe und dann den Status mit einer Versionsnummer einfrieren kann, trotzdem aber die Meldungen aus den Funktionen zeitnah (also direkt nach Auftreten) verarbeiten kann. Und diese Verarbeitung soll eben nach Willen des "main" bzw. der Hauptapplikation passieren.

Bearbeitet von Janosh
Link zu diesem Kommentar
Auf anderen Seiten teilen

Wieviele Instanzen deiner Klasse existieren denn gleichzeitig? Spricht etwas dagegen, einen statischen Instanzzeiger zu benutzen, über den du dann in der statischen Methode an die Instanz herankommst?

Ich habe von meiner Klasse nur 1 Instanz. Das würde die Idee mit einem statischen Instanzpointer realisierbar machen. Muss ich ausprobieren.

Wenn dieses "Objekt" in C geschrieben ist, kann es mit einer C++-Klassendefinition sowieso nichts anfangen.

Deshalb kann ich ja auch die Klasse darin nicht bekanntgeben (was ich eh nicht gewollt hätte, auch wenn es in CPP geschrieben wäre).

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi nochmal,

ich habe zur Verdeutlichung jetzt mal mein Problem in einer neuen Solution zusammengefasst.

Vielleicht könnt ihr ja mehr damit anfangen, wenn ihr das Problem in Code vor euch habt.

Ich wär euch wirklich sehr dankbar, wenn ihr mir helfen könntet, eine Lösung für mein Problem zu finden. Gerne auch direkt in Quellcode.

Danke und viele Grüße,

Janosh

LogError.zip

Link zu diesem Kommentar
Auf anderen Seiten teilen

Man kann der C-Funktion noch einen weiteren Zeiger übergeben und den Aufruf an die jeweilige Klasseninstanz über eine Hilfsfunktion, die den zweiten übergebenen Zeiger als Parameter erhält, selbst vermitteln, die nicht mehr Teil der C-Funktionssammlung ist und somit auch die Klassendefinition kennen darf.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das sieht doch schon ganz gut aus. Ich hätte den Instanzzeiger als static-Member umgesetzt, aber so geht es auch.

Allerdings solltest du dir nochmal klarmachen, was static bewirkt, wenn es nicht innerhalb einer Klasse oder Funktion steht. Du hast Obj01_WriteInLogFile als static (auf Dateiebene) deklariert. Dadurch hat jede Übersetzungseinheit ( = .cpp-Datei), in der diese Deklaration auftaucht, eine eigene Variable Obj01_WriteInLogFile. Es gibt also ein Obj01_WriteInLogFile für Object.cpp, und eins für LogErrorDlg.cpp, und diese beiden haben nichts miteinander zu tun.

Wenn du also in LogErrorDlg.cpp den Funktionszeiger setzt, ist der in Object.cpp immer noch NULL.

Du musst Obj01_WriteInLogFile in Object.h nicht als static, sondern als extern deklarieren, und dann noch in Object.cpp ohne irgendeinen Speicherklassenspezifizierer definieren.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das sieht doch schon ganz gut aus. Ich hätte den Instanzzeiger als static-Member umgesetzt, aber so geht es auch.

Ehrlich gesagt, wo der in bzw. nicht in meiner Klasse steht, war mir jetzt erstmal egal. Es ging um funktionieren oder nicht.

Allerdings solltest du dir nochmal klarmachen, was static bewirkt, wenn es nicht innerhalb einer Klasse oder Funktion steht. Du hast Obj01_WriteInLogFile als static (auf Dateiebene) deklariert. Dadurch hat jede Übersetzungseinheit ( = .cpp-Datei), in der diese Deklaration auftaucht, eine eigene Variable Obj01_WriteInLogFile. Es gibt also ein Obj01_WriteInLogFile für Object.cpp, und eins für LogErrorDlg.cpp, und diese beiden haben nichts miteinander zu tun.

Wenn du also in LogErrorDlg.cpp den Funktionszeiger setzt, ist der in Object.cpp immer noch NULL.

Danke für die Erklärung. Ich hab gemeint, dass es eine Instanz für beide CPPs ist. Denkfehler meinerseits.

Du musst Obj01_WriteInLogFile in Object.h nicht als static, sondern als extern deklarieren, und dann noch in Object.cpp ohne irgendeinen Speicherklassenspezifizierer definieren.

Genau die Definition hat mir in meiner ganzen Rumprobiererei immer gefehlt. Damit funktioniert es endlich.

Ich hab es sogar noch so erweitert, dass ich in der Object.cpp eine leere Dummyfunktion definiert hab, auf die der Funktionspointer anfangs zeigt, damit ich im Falle einer Nicht-Initialisierung des Pointers im Main keinen Absturz wegen Schreiben an Adresse 0000 bekomme.

Nochmal herzlichen Dank an alle für die schnelle und so ausführliche Hilfe. Ich hab wieder ne Menge gelernt und vor allem mein Problem lösen können.

Ihr seid klasse.

Liebe Grüße,

Janosh

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...