Frage

Ich habe googeln um, und ich kann einfach nicht eine einfache Antwort auf diese finden. Und es sollte einfach sein, da die STL im Allgemeinen ist.

Ich möchte MyOStream definieren, die öffentlich von std :: ostream erbt. Sagen wir, ich möchte foo () aufrufen, jedes Mal etwas geschrieben in meinem Stream.

class MyOStream : public ostream {
public:
  ...
private:
   void foo() { ... }
}

Ich verstehe, dass die öffentliche Schnittstelle von ostream ist nicht virtuell, so wie es getan werden kann? Ich möchte Kunden sowohl Betreiber nutzen können << und schreiben () und put () auf MyOStream und haben die erweiterte Fähigkeit meiner Klasse.

War es hilfreich?

Lösung

Es ist keine einfache Frage, leider. Die Klassen, die Sie leiten sollten aus sind die basic_ Klassen wie basic_ostream. Allerdings Ableitung aus einem Stream kann nicht sein, was Sie wollen, können Sie aus einem Stream-Puffer statt, abzuleiten und dann diese Klasse verwenden, um eine bestehende Stream-Klasse zu instanziiert.

Die ganze Gegend ist sehr komplex, aber es ist ein ausgezeichnetes Buch über sie Standard C ++ iostreams und Locales , die ich schlage vor, Sie an, bevor es weiter geht einen Blick darauf werfen.

Andere Tipps

Ich drehte meinen Kopf herum, wie die gleiche Sache zu tun, und ich fand heraus, es ist eigentlich nicht so schwer. Im Grunde genommen nur die Unterklasse Ostream und die streambuf Objekte und konstruiert die Ostream mit mir selbst als Puffer. der virtuelle Überlauf () von std :: streambuf wird in den Stream gesendet für jedes Zeichen bezeichnet werden. Passen Ihrem Beispiel ich habe gerade einen foo () Funktion und nannte es.

struct Bar : std::ostream, std::streambuf
{
    Bar() : std::ostream(this) {}

    int overflow(int c)
    {
        foo(c);
        return 0;
    }


    void foo(char c)
    {
        std::cout.put(c);

    }
};

void main()
{
    Bar b;
    b<<"Look a number: "<<std::hex<<29<<std::endl;
}

ach ja, und ignoriert die Tatsache, dass die Hauptfunktion keine wirkliche Hauptfunktion ist. Es ist in einem Namensraum von anderswo genannt; p

Ein weiterer Arbeits Hack um einen ähnlichen Effekt zu erreichen, ist Schablone und Zusammensetzung zu verwenden,

class LoggedStream {
public:
  LoggedStream(ostream& _out):out(_out){}
  template<typename T>
  const LoggedStream& operator<<(const T& v) const {log();out << v;return *this;}
protected:
  virtual void log() = 0;
  ostream& out;
};

class Logger : LoggedStream {
  void log() { std::cerr << "Printing" << std::endl;}
};

int main(int,char**) {LoggedStream(std::cout) << "log" << "Three" << "times";}

Ich weiß nicht, ob diese richtige Lösung ist, aber ich geerbt von std :: ostream auf diese Weise. Es verwendet einen Puffer geerbt von std :: basic_streambuf und bekommt 64 Zeichen in einer Zeit (oder weniger, wenn gespült) und sendet sie an einen generischen putChars () -Methode, wo die eigentliche Verarbeitung der Daten erfolgt. Es zeigt auch, wie die Benutzerdaten geben.

anschauliches Beispiel

#include <streambuf>
#include <ostream>
#include <iostream>

//#define DEBUG

class MyData
{
    //example data class, not used
};

class MyBuffer : public std::basic_streambuf<char, std::char_traits<char> >
{

public:

    inline MyBuffer(MyData data) :
    data(data)
    {
        setp(buf, buf + BUF_SIZE);
    }

protected:

    // This is called when buffer becomes full. If
    // buffer is not used, then this is called every
    // time when characters are put to stream.
    inline virtual int overflow(int c = Traits::eof())
    {
#ifdef DEBUG
        std::cout << "(over)";
#endif
        // Handle output
        putChars(pbase(), pptr());
        if (c != Traits::eof()) {
            char c2 = c;
            // Handle the one character that didn't fit to buffer
            putChars(&c2, &c2 + 1);
        }
        // This tells that buffer is empty again
        setp(buf, buf + BUF_SIZE);

        return c;
    }

    // This function is called when stream is flushed,
    // for example when std::endl is put to stream.
    inline virtual int sync(void)
    {
        // Handle output
        putChars(pbase(), pptr());
        // This tells that buffer is empty again
        setp(buf, buf + BUF_SIZE);
        return 0;
    }

private:

    // For EOF detection
    typedef std::char_traits<char> Traits;

    // Work in buffer mode. It is also possible to work without buffer.
    static const size_t BUF_SIZE = 64;
    char buf[BUF_SIZE];

    // This is the example userdata
    MyData data;

    // In this function, the characters are parsed.
    inline void putChars(const char* begin, const char* end){
#ifdef DEBUG
        std::cout << "(putChars(" << static_cast<const void*>(begin) <<
            "," << static_cast<const void*>(end) << "))";
#endif
        //just print to stdout for now
        for (const char* c = begin; c < end; c++){
            std::cout << *c;
        }
    }

};

class MyOStream : public std::basic_ostream< char, std::char_traits< char > >
{

public:

    inline MyOStream(MyData data) :
    std::basic_ostream< char, std::char_traits< char > >(&buf),
    buf(data)
    {
    }

private:

    MyBuffer buf;

};

int main(void)
{
    MyData data;
    MyOStream o(data);

    for (int i = 0; i < 8; i++)
        o << "hello world! ";

    o << std::endl;

    return 0;
}

Zusammensetzung, nicht Vererbung. Ihre Klasse enthält, "wickelt" eine ostream &, und nach vorn, um es (nach dem Aufruf von foo ()).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top