C ++装饰basic_iostream类 [英] C++ Decorate basic_iostream classes

查看:586
本文介绍了C ++装饰basic_iostream类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做类似以下代码的操作:

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

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

foo&写(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->
}
else
{
// ...
}

return * this;
}
};

我需要为所有类似的方法添加相同的行为(例如 put )。这不应该仅应用于文件流,而是应用于所有其他流类。

解决方案

许多格式化的输出操作符( operator< < )直接写入底层流缓冲区。为了以一般方式实现这一点,你需要做的是从std :: basic_streambuf派生一个类,将所有数据转发到另一个std :: basic_streambuf,然后可选地创建一个最小的std :: basic_ostream实现使用你的流缓冲区更容易。



我不会说这是特别容易,但它是唯一的方式,这样做可以影响所有的流类型。 p>

这里是一个最小流缓冲区的示例,它转发到另一个流缓冲区(并执行一些无意义的转换,只是为了演示你可以做什么)和一个伴随的流: p>

  #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)
{
}


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 ++; //做一些无意义的转换
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> _缓冲;
};

这可以很简单地使用:

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

这将输出 Gpp 。我希望这可以帮助你的路上。


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?

解决方案

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.

这篇关于C ++装饰basic_iostream类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆