Наследование от std:: basic streambuf для записи в сокет

Я хотел бы написать собственную библиотеку журналов, которая обеспечивает абстракцию для того, куда отправляются записи журнала.

библиотека ввода-вывода C++ уже предоставляет такую абстракцию с std::stringstream и std::fstream. Я также хотел бы иметь возможность читать/писать из/в сокет.

Я читал, что правильный способ расширения стандартной библиотеки наследуются от std::basic_streambuf. Чего я не понимаю, так это, если наследование от std::basic_streambuf как std::basic_filebuf делает, где находится потребность в std::ifsream, std::ofstream и std::fstream классы ? Не могу ли я просто заменить буфер некоторого потока экземпляром подкласса std::basic_streambuf какие выходы, где я хочу ?

до сих пор я делал следующее, Но я действительно не уверен в том, что я делаю. Следующая конструкция правильная ?

template< typename char_type, typename traits_type = std::char_traits< char_type > >
class basic_sock_streambuf : public std::basic_streambuf< char_type, traits_type >
{
public:

    basic_sock_streambuf()
    {

    }

    ~basic_sock_streambuf()
    {

    }

    int overflow (int c = EOF)
    {
        fputc( c, stdout ); // Temporary.
        return traits_type::to_int_type( c );
    }

    int underflow()
    {
        return fgetc( stdout ); // Temporary.
    }

    int sync()
    {
        return 0;
    }
};

template< typename char_type, typename traits_type = std::char_traits< char_type > >
class basic_isockstream : public std::basic_istream< char_type, traits_type >
{
};

template< typename char_type, typename traits_type = std::char_traits< char_type > >
class basic_osockstream : public std::basic_ostream< char_type, traits_type >
{
};

template< typename char_type, typename traits_type = std::char_traits< char_type > >
class basic_socktream : public basic_isockstream< char_type, traits_type >, public basic_osockstream< char_type, traits_type >
{
private:

    typedef basic_isockstream< char_type, traits_type > iparent;

    typedef basic_osockstream< char_type, traits_type > oparent;

    basic_sock_streambuf< char_type, traits_type > sock_sb;

    std::basic_streambuf< char_type, traits_type > * old_isb;

    std::basic_streambuf< char_type, traits_type > * old_osb;

public:

    basic_socktream()
    {
        old_isb = iparent::rdbuf( & sock_sb );
        old_osb = oparent::rdbuf( & sock_sb );
    }

    ~basic_socktream() throw()
    {
        iparent::rdbuf( old_isb );
        oparent::rdbuf( old_osb );
    }
};

EDIT: код обновлен на основе ответов:

template<
    typename char_type,
    typename traits_type = std::char_traits< char_type > >
class basic_sockbuf :
    public std::basic_streambuf< char_type, traits_type >
{
public:

    basic_sockbuf()
    {
    }

    ~basic_sockbuf()
    {
    }

    int overflow( int c = EOF )
    {
        fputc( c, stdout ); // Temporary.
        return traits_type::to_int_type( c );
    }

    int underflow()
    {
        return fgetc( stdout ); // Temporary.
    }

    int sync()
    {
        return 0;
    }
};

template<
    typename char_type,
    typename traits_type = std::char_traits< char_type > >
class basic_isockstream :
    public std::basic_istream< char_type, traits_type >
{
private:

    typedef std::basic_istream< char_type, traits_type > parent;

    basic_sockbuf< char_type, traits_type > buffer;

public:

    basic_isockstream() :
        std::basic_istream< char_type, traits_type >::basic_istream(),
        buffer()
    {
        init( & buffer );
    }
};

template<
    typename char_type,
    typename traits_type = std::char_traits< char_type > >
class basic_osockstream :
    public std::basic_ostream< char_type, traits_type >
{
private:

    basic_sockbuf< char_type, traits_type > buffer;

public:

    basic_osockstream() :
        std::basic_ostream< char_type, traits_type >::basic_istream(),
        buffer()
    {
        init( & buffer );
    }
};

template<
    typename char_type,
    typename traits_type = std::char_traits< char_type > >
class basic_socktream :
    public std::basic_iostream< char_type, traits_type >,
    public basic_sockbuf< char_type, traits_type >
{
private:

    basic_sockbuf< char_type, traits_type > buffer;

public:

    basic_socktream() :
        std::basic_iostream< char_type, traits_type >::basic_iostream(),
        buffer()
    {
        std::basic_iostream< char_type, traits_type >::init( & buffer );
    }
};

1 ответов


std::istream и std::ostream обеспечить форматированные операции ввода и вывода. То есть преобразование потока в/из чисел, строк и т. д...

std::basic_streambuf - это интерфейс нижнего уровня, который считывает или записывает фрагменты символов В или из ...где-то. Это то, что вам нужно для подкласса и реализации.

и вы на правильном пути. Оба!--0--> и std::ostream имеют перегруженный конструктор, который принимает указатель на буфер потока. Итак, ваш план действий есть:

  1. подкласс и реализовать свой пользовательский std::basic_streambuf.

  2. построить std::istream или std::ostream использование указателя на буфер потока.

не могу ли я просто заменить буфер некоторого потока экземпляром подкласс std::basic_streambuf

нет, не заменить, а построить. Вы создаете std::istream или std::ostream, используя указатель на свой буфер. Вы не будете используйте std::[io]fstream, а std::istream и std::ostream, построен с использованием буфера потока.

все это a std::ifstream is, например, является подклассом std::istream который создает свой суперкласс с указателем на внутренний буфер потока, который считывает из файла.

не стесняйтесь создавать свой собственный подкласс std::istream, который multiply-наследуется от вашего подкласса буфера потока, и std::istream, сначала создает подкласс буфера потока, затем std::istream.