stdin über eigene Bufferklasse umleiten?
-
Hallo,
inspiriert durch CStolls Artikel über die C++ IO Streams bin ich zurzeit am Implementieren einer eigenen Eventklasse. Ziel ist es, über ein Interface, realisiert durch eine abstrakte Basisklasse, einen Eventhandler anzumelden. Wenn ein Event eintritt (z.B. ein bestimmter Tastendruck), dann soll die von der Basisklasse überladene Funktion der zuvor registierten Klasse aufgerufen werden. Nun möchte ich idealerweise den Standardinput an meine Klasse leiten, die die relevanten Informationen filtert, und sie an std::streambuf wie gewohnt weiterleitet. Aber wie stelle ich das an? Nachfolgend der Code:
#include <iostream> #include <string> // Eventinterface class EventInterface { public: virtual void OnEvent (const std::string &text) = 0; }; // Über diese Klasse soll der Standardinput geleitet werden: class EventHandlerCtrl { private: EventInterface *Handler; public: void AddEventHandle (EventInterface *Handler) { this->Handler = Handler; } void StartEventMonitor () { // Hier soll der Standardinput gefiltert werden, und beim Eintreten eines // Events die Funktion der angemeldeten Klasse aufgerufen werden: Handler->OnEvent ("Hallo, aus der Derived Class!"); } }; // Die Klasse, die später beim Eventhandler angemeldet wird: class WorkingClass : public EventInterface { private: EventHandlerCtrl api; public: // Diese Funktion soll beim Auftreten eines Events bzw. Tastendrucks aufgerufen werden: void OnEvent (const std::string &text) { std::cout << "The following event has occurred: " << text << std::endl; } void RegisterEvent () { api.AddEventHandle (this); api.StartEventMonitor (); } }; int main () { WorkingClass *derive = new WorkingClass; derive->RegisterEvent (); }Für Literaturquellen, oder jeglichen anderen Hinweisen bin ich euch sehr dankbar!
-
edit: Doch nicht, sorry

-
Genau den selben Artikel habe ich mir auch durchgelesen :p Aber mein Ziel ist ja nicht die Datei, sondern meine Klasse (womöglich abgeleitet von streambuf, keine Ahnung, das ist ja meine Frage). Trotzdem thx!
-
Ok, also ich glaube, den stdin-Stream kannst du nicht in was anderes als eine Datei umleiten. Eventuell kannst du aber cin so beeinflussen, dass du die Datenherkunft beeinflussen kannst. Du kannst ja z.B. (dirty, dirty :D)
istream& operator>> ( istream& stream, const string& text )überladen und mitif ( stream == cin )prüfen, ob der Stream auch das cin-Objekt ist. Zwischendurch kannst du den Zielstream umleiten.. Hab mich komisch ausgedrückt, aber verstehst was ich meine?
-
Das klappt so nicht.
-
Badestrand schrieb:
Du kannst ja z.B. (dirty, dirty ) istream& operator>> ( istream& stream, const string& text ) überladen und mit if ( stream == cin ) prüfen, ob der Stream auch das cin-Objekt ist.
Also entweder ich verstehe dich nicht, oder du verstehst mich nicht
Das kann so nicht klappen, wie du es mir beschrieben hast. Wenn ich den >> Operator überlade, muss ihn der Anwender auch zwangsläufig anwenden, damit meine Klasse überhaupt irgendwelche Eingaben registiert. Und das Objekt kann auch nur immer vom selben Typ meiner Klasse sein (this). Oder wie meinst du das? Könntest du mir ein konkretes Codebeispiel schreiben?
-
Ok, ich schätze mal, ich hab dich falsch verstanden

Naja, hier das hab ich trotzdem grad mal zusammengeschustert:
#include <iostream> #include <string> using namespace std; #define null 0 class StreamReader { public: virtual void read( char* buffer, streamsize count ) = 0; }; static StreamReader* in_stream = null; void RedirectInput( StreamReader* in=null ) { in_stream = in; } istream& operator>> ( istream& stream, string& text ) { if ( stream == cin && in_stream) { text = ""; char c = '\0'; do { in_stream->read( &c, 1 ); if ( c != '\0' ) text.push_back( c ); } while ( c != '\0' ); } else { for ( char c='\0'; c!='\r' && c!='\n'; cin.read(&c,1) ) text.push_back( c ); } return stream; } class MyDataSender : public StreamReader { public: MyDataSender( const string& to_transmit ) : text(to_transmit), done(0) { } virtual void read( char* buffer, streamsize num ) { for ( streamsize i=0; i<num; i++, done++ ) { if ( done >= text.size() ) buffer[i] = '\0'; else buffer[i] = text[done]; } } private: size_t done; string text; }; int main() { MyDataSender sender( "Hallo" ); string text; cin >> text; cout << text << endl; RedirectInput( &sender ); cin >> text; cout << text << endl; return 0; }Dabei müsstest du dann halt die Deklarationen der istream-Überladungen in den Anwenderdateien bekannt machen... Aber wie gesagt, ich hab dich falsch verstanden

-
Nette Technik, habe ich auch noch nie gesehen :p Aber wie du schon gesagt hast, das ist nicht das, was ich versuche. Trotzdem danke ich dir für deine Mühe. Ich stelle mir das ungefähr so vor, wenn man meine Klasse anwendet:
// Ab hier soll der Input über meine Klasse umgeleitet werden WorkingClass::StartEventMonitor (); std::string eingabe; // Diese Eingabe soll von meiner Klasse registriert werden, so als wäre es also der klasseneigene, überladene >> Operator: std::cin >> eingabe; // ...Eventuell hat dazu noch jemand eine Idee? Laut CStolls Artikel muss ja sowas mehr oder weniger machbar sein, zumindest stelle ich mir das so vor.
-
Du brauchst einfach für cin deine eigene Stream-Puffer-Implementierung angeben:
mystreambuf buf; cin.rdbuf(buf); // setze den Puffer neuHier ein Link (funktioniert analog auch für cin):
http://www.josuttis.de/cppbuch/io/redirect.cpp.htmlNun mußt du dir noch die Klasse streambuf anschauen und deine eigene Implementierung erzeugen. (habe dafür leider keinen Link -)
-
Hey super, danke Th! Mein Dank gebührt auch Badestrand
