Cómo heredar de std::ostream?


He estado buscando en Google y no puedo encontrar una respuesta simple a esto. Y debe ser simple, como el STL generalmente es.

Quiero definir MyOStream que hereda públicamente de std::ostream. Digamos que quiero llamar a foo () cada vez que algo se escribe en mi flujo.

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

Entiendo que la interfaz pública de ostream no es virtual, así que ¿cómo se puede hacer? Quiero que los clientes puedan usar operator

Author: Michael, 2009-04-21

5 answers

Desafortunadamente, no es una pregunta sencilla. Las clases de las que debe derivar son las clases basic_, como basic_ostream. Sin embargo, la derivación de una secuencia puede no ser lo que desea, es posible que desee derivar de un búfer de secuencia en su lugar, y luego usar esta clase para instanciar una clase de secuencia existente.

Toda el área es compleja, pero hay un excelente libro sobre ella Standard C++ IOStreams and Locales, que le sugiero que eche un vistazo antes de ir más lejos.

 23
Author: Qix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-10 03:36:40

Otro truco de trabajo para lograr un efecto similar es usar plantilla y composición

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";}
 21
Author: Elazar Leibovich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-11 15:20:18

Estaba pensando en cómo hacer lo mismo y descubrí que en realidad no es tan difícil. Básicamente solo subclase los objetos ostream y streambuf, y construya el ostream consigo mismo como el búfer. el virtual overflow () de std::streambuf será llamado para cada carácter enviado a la secuencia. Para encajar en tu ejemplo acabo de hacer una función foo () y la llamé.

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;
}

Oh e ignorar el hecho de que la función principal no es una función principal real. Está en un espacio de nombres llamada desde otro lugar; p

 18
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-12 15:36:42

No se si esta es la solución correcta, pero he heredado de std::ostream de esta manera. Utiliza un búfer heredado de std:: basic_streambuf y obtiene 64 caracteres a la vez (o menos si se vacía) y los envía a un método genérico putChars () donde se realiza el manejo real de los datos. También demuestra cómo proporcionar datos de usuario.

Ejemplo en vivo

#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;
}
 5
Author: Henrik Heino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-28 23:41:33

Composición, no herencia. Tu clase contiene," envuelve " un ostream& y lo reenvía (después de llamar a foo ()).

 0
Author: tpdi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-21 12:44:47