C++装饰 basic_iostream 类

发布于 2024-11-15 22:22:02 字数 710 浏览 3 评论 0原文

我想做类似以下代码所示的事情:

class foo
{
private:
    std::fstream* m_stream;

public:
    foo(std::fstream* stream) : m_stream(stream) { }

    foo& write(char const* s, std::streamsize count)
    {
        if (/*condition*/)
        {
            m_stream->write(s, count);
        }
        else
        {
            // ...
        }

        return *this;
    }

    foo& read(char* s, std::streamsize count)
    {
        if (/*condition*/)
        {
            m_stream->read(s, count);
        }
        else
        {
            // ...
        }

        return *this;
    }
};

我需要向所有类似的方法添加相同的行为(例如 put)。这不应仅应用于文件流,而应应用于所有其他流类。有没有简单的方法来允许这些功能?

I want to do something like the following code shows:

class foo
{
private:
    std::fstream* m_stream;

public:
    foo(std::fstream* stream) : m_stream(stream) { }

    foo& write(char const* s, std::streamsize count)
    {
        if (/*condition*/)
        {
            m_stream->write(s, count);
        }
        else
        {
            // ...
        }

        return *this;
    }

    foo& read(char* s, std::streamsize count)
    {
        if (/*condition*/)
        {
            m_stream->read(s, count);
        }
        else
        {
            // ...
        }

        return *this;
    }
};

I would need to add the same behavior to all similar methods (e.g. put). This shouldn't be applied to file streams only, but all other stream classes. Is there any easy way to allow these functionality?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

情话墙 2024-11-22 22:22:02

许多格式化输出运算符 (operator<<) 直接写入底层流缓冲区。为了以一般方式完成此任务,您需要做的是从 std::basic_streambuf 派生一个类,它将所有数据转发到另一个 std::basic_streambuf,然后选择创建一个最小的 std::basic_ostream 实现来使用您的流缓冲更容易。

不过,我不会说这特别容易,但这是以可以影响所有流类型的方式做到这一点的唯一方法。

下面是一个最小流缓冲区的示例,它转发到另一个流缓冲区(并执行一些无意义的转换,只是为了演示您可以做什么),以及一个附带的流:

#include <iostream>
#include <streambuf>

template<typename CharType, typename Traits = std::char_traits<CharType> >
class ForwardingStreamBuf : public std::basic_streambuf<CharType, Traits>
{
public:
    typedef Traits traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;

    ForwardingStreamBuf(std::basic_streambuf<CharType, Traits> *baseStreamBuf)
        : _baseStreamBuf(baseStreamBuf)
    {
    }

protected:
    virtual int_type overflow(int_type c = traits_type::eof())
    {
        if( _baseStreamBuf == NULL )
            return traits_type::eof();

        if( traits_type::eq_int_type(c, traits_type::eof()) )
            return traits_type::not_eof(c);
        else
        {
            CharType ch = traits_type::to_char_type(c);
            if( ch >= 'A' && ch <= 'z' )
                ch++; // Do some meaningless transformation
            return _baseStreamBuf->sputc(ch);
        }
    }

    virtual int sync()
    {
        if( _baseStreamBuf == NULL )
            return -1;
        else
            return _baseStreamBuf->pubsync();
    }
private:
    std::basic_streambuf<CharType, Traits> *_baseStreamBuf;
};

template<typename CharType, typename Traits = std::char_traits<CharType> >
class ForwardingStream : public std::basic_ostream<CharType, Traits>
{
public:
    ForwardingStream(std::basic_ostream<CharType, Traits> &stream)
        : std::basic_ostream<CharType, Traits>(NULL), _buffer(stream.rdbuf())
    {
        this->init(&_buffer);
    }

    ForwardingStreamBuf<CharType, Traits>* rdbuf() const
    {
        return &_buffer;
    }
private:
    ForwardingStreamBuf<CharType, Traits> _buffer;
};

这可以非常简单地使用:

int main()
{
    ForwardingStream<char> test(std::cout);
    test << "Foo" << std::endl;
}

它将输出 Gpp< /代码>。我希望这对您有所帮助。

Many of the formatted output operators (operator<<) write directly to the underlying stream buffer. What you need to do in order to accomplish this in a general fashion is derive a class from std::basic_streambuf that forwards all data to another std::basic_streambuf, and then optionally create a minimal std::basic_ostream implementation to make using your stream buffer easier.

I wouldn't say this is particularly easy, though, but it's the only way to do this in a way that can affect all stream types.

Here is an example of a minimal stream buffer that forwards to another stream buffer (and performs some meaningless transformation just to demonstrate what you can do), and an accompanying stream:

#include <iostream>
#include <streambuf>

template<typename CharType, typename Traits = std::char_traits<CharType> >
class ForwardingStreamBuf : public std::basic_streambuf<CharType, Traits>
{
public:
    typedef Traits traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;

    ForwardingStreamBuf(std::basic_streambuf<CharType, Traits> *baseStreamBuf)
        : _baseStreamBuf(baseStreamBuf)
    {
    }

protected:
    virtual int_type overflow(int_type c = traits_type::eof())
    {
        if( _baseStreamBuf == NULL )
            return traits_type::eof();

        if( traits_type::eq_int_type(c, traits_type::eof()) )
            return traits_type::not_eof(c);
        else
        {
            CharType ch = traits_type::to_char_type(c);
            if( ch >= 'A' && ch <= 'z' )
                ch++; // Do some meaningless transformation
            return _baseStreamBuf->sputc(ch);
        }
    }

    virtual int sync()
    {
        if( _baseStreamBuf == NULL )
            return -1;
        else
            return _baseStreamBuf->pubsync();
    }
private:
    std::basic_streambuf<CharType, Traits> *_baseStreamBuf;
};

template<typename CharType, typename Traits = std::char_traits<CharType> >
class ForwardingStream : public std::basic_ostream<CharType, Traits>
{
public:
    ForwardingStream(std::basic_ostream<CharType, Traits> &stream)
        : std::basic_ostream<CharType, Traits>(NULL), _buffer(stream.rdbuf())
    {
        this->init(&_buffer);
    }

    ForwardingStreamBuf<CharType, Traits>* rdbuf() const
    {
        return &_buffer;
    }
private:
    ForwardingStreamBuf<CharType, Traits> _buffer;
};

This can be used very simply:

int main()
{
    ForwardingStream<char> test(std::cout);
    test << "Foo" << std::endl;
}

Which would output Gpp. I hope that helps you on your way.

动听の歌 2024-11-22 22:22:02

像这样的东西吗?

   template <class Stream>
    class DecoratedStream {
    public:
      DecoratedStream(Stream* stream) : m_stream(stream) {}

      DecoratedStream& write(const char* data, int count) {
        m_stream->write(data, count);
      }

    };

Something like this?

   template <class Stream>
    class DecoratedStream {
    public:
      DecoratedStream(Stream* stream) : m_stream(stream) {}

      DecoratedStream& write(const char* data, int count) {
        m_stream->write(data, count);
      }

    };
岁月静好 2024-11-22 22:22:02

如果我理解正确的话,您想装饰任何 iostream 的方法。因此,只需让您的装饰器采用 iostream 来作为装饰者(而不是 fstream ,它是 iostream 的子类)。

If I understand you correctly, you want to decorate methods of any iostream. So just make your decorator take an iostream as decoratee (as opposed to an fstream, which is a subclass of iostream).

落日海湾 2024-11-22 22:22:02

作为当前的方法,将指针放在结构内部是危险且容易出错的。相反,只需派生此类 stream 类并实现基本构造函数并包装您的自定义方法,例如 write()

template<typename StreamType>
class foo : StreamType
{
  // wrapper constructors supporting StreamType() constructors
  foo& write(char const* s, std::streamsize count)
  {
    //...
    return *this;
  }
};

用法:

foo<fstream> obj;
obj.write(...);

Having pointer inside a structure as your current approach is dangerous and error prone. Instead just derive such stream classes and implement basic constructors and wrap around your custom methods such as write().

template<typename StreamType>
class foo : StreamType
{
  // wrapper constructors supporting StreamType() constructors
  foo& write(char const* s, std::streamsize count)
  {
    //...
    return *this;
  }
};

Usage:

foo<fstream> obj;
obj.write(...);
挖鼻大婶 2024-11-22 22:22:02

解决此类问题的通常方法是使用模板。那里
std::istreamstd::ostream 中的函数不是很多吗
需要覆盖,并且
<<>>的良好模板成员应该
涵盖了很多案例。在大多数情况下我都这样做了
仅提供
<<>>`。 (一般来说,我不需要
双向流。)

至于处理其他类型的流,只需使用 std::iostream 即可
std::fstream。 (一般来说,除了打开文件时,您
不应该看到 fstream 部分。)

The usual solution for this sort of problem is to use templates. There
aren't that many functions in an std::istream or and std::ostream
which need covering, and a good template member for
<<and>>should
cover a lot of the cases. In most of the cases I've done this, I've
only offerred
<<or>>`. (Generally speaking, I've not needed
bidirectional streams.)

As for handling other types of streams, just use std::iostream instead
of std::fstream. (In general, except when opening files, you
shouldn't see the fstream part.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文