问题描述
|
我想通过使用装饰器模式来扩展basic_streambuf对象的行为。那就是我目前得到的:
template<typename char_type,class traits_type>
class forwarding_basic_streambuf
: boost::noncopyable,public std::basic_streambuf<char_type,traits_type>
{
public:
typedef std::basic_streambuf<char_type,traits_type> forwarded_type;
forwarding_basic_streambuf(forwarded_type& fwd_buf)
: m_fwd(&fwd_buf) { }
virtual ~forwarding_basic_streambuf() { }
// locales:
// std::locale pubimbue(std::locale const& loc);
// => Calls: imbue(loc) | Returns: PrevIoUs value of getloc();
// std::locale getloc () const;
// => Returns: If pubimbue() has ever been called,then the last value of loc supplied,otherwise the
// current global locale,locale(),in effect at the time of construction. If called after
// pubimbue() has been called but before pubimbue has returned (i.e.,from within the call
// of imbue()) then it returns the prevIoUs value.
// buffer management and positioning:
// forwarded_type* pubsetbuf (char_type* s,std::streamsize n); => Returns: setbuf(s,n)
// pos_type pubseekoff(off_type off,std::ios_base::seekdir way,// std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
// => Returns seekoff(off,way,which)
// pos_type pubseekpos(pos_type sp,// std::ios_base::openmode which = std::ios_base::in | std::ios_base::out);
// => Returns: seekpos(sp,which)
// int pubsync (); => Returns: sync()
// get and put areas:
// get area:
// std::streamsize sgetn (char_type* s,std::streamsize n); => Returns: xsgetn(s,n)
// put area:
// std::streamsize sputn(char_type const* s,std::streamsize n); => Returns: xsputn(s,n)
protected:
// virtual functions:
// locales:
virtual void imbue(std::locale const& loc) { this->m_fwd->pubimbue(loc); }
// buffer management and positioning:
virtual forwarded_type* setbuf (char_type* s,std::streamsize n)
{ return this->m_fwd->pubsetbuf(s,n); }
virtual pos_type seekoff(off_type off,std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
{ return this->m_fwd->pubseekoff(off,way); }
virtual pos_type seekpos(pos_type sp,std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
{ return this->m_fwd->pubseekpos(sp,which); }
virtual int sync ()
{ return this->m_fwd->pubsync(); }
// get and put areas:
// get area:
virtual std::streamsize xsgetn(char_type* s,std::streamsize n)
{ return this->m_fwd->sgetn(s,n); }
virtual int_type uflow()
{
if (traits_type::eq_int_type(this->underflow(),traits_type::eof()))
return traits_type::eof();
return this->m_fwd->sgetc();
}
// put area:
virtual std::streamsize xsputn (char_type const* s,std::streamsize n)
{ return this->m_fwd->sputn(s,n); }
virtual int_type overflow(int_type c = traits_type::eof())
{
if (traits_type::eq_int_type(c,traits_type::eof()))
return traits_type::not_eof(c);
return this->m_fwd->sputc(traits_type::to_char_type(c));
}
private:
forwarded_type* m_fwd;
};
基本目标(作为第一步)将是简单地将每个功能转发到装饰对象。因此,即使有指向它的基类的指针,也应该可以使用该装饰器。
一切对于编写方法都可以正常工作,但是我不知道如何处理underflow()函数,该函数从uflow()和sgetc()调用。
解决方法
我可能会丢失一些东西,但是您的设计对我来说没有多大意义。
如我所见,扩展ѭ1是通过覆盖受保护的虚拟接口来完成的,如果您想使用装饰器模式,则装饰器基类将仅执行此操作。
template<typename char_type,class traits_type>
class forwarding_basic_streambuf
: boost::noncopyable,public std::basic_streambuf<char_type,traits_type>
{
public:
typedef std::basic_streambuf<char_type,traits_type> forwarded_type;
forwarding_basic_streambuf(forwarded_type& fwd_buf)
: m_fwd(&fwd_buf) { }
virtual ~forwarding_basic_streambuf() { }
protected:
virtual streamsize xsputn ( const char * s,streamsize n ) {
m_fwd->xsputn(s,n);
}
virtual int overflow ( int c) {
m_fwd->overflow(c);
}
// etc.
};
然后,您真正的实现会添加任何所需的“装饰”,例如
template<typename char_type,class traits_type>
class add_timestamp_decorator
: public forwarding_basic_streambuf<char_type,traits_type>
{
public:
typedef std::forwarding_basic_streambuf<char_type,traits_type> base_type;
add_timestamp_decorator(base_type::forwarded_type& fwd_buf)
: base_type(&fwd_buf) { }
virtual ~add_timestamp_decorator() { }
protected:
virtual streamsize xsputn ( const char * s,streamsize n ) {
// detect and remember when a newline is written
// before the next char is written output the timestamp
base_type::xsputn(s,n);
}
// etc.
};
然后在输出流上使用它(伪代码,为清楚起见省略了模板定义)
ostream outputstream;
// ....
add_timestamp_decorator decorator = new add_timestamp_decorator(outputstream.rdbuf());
outputstream.rdbuf(decorator);
outputstream << \"some lines\\ntimestamps will be inserted\\n\\n\";
, 规范以下列方式描述“ 5”(27.6.3.4.3。[15-17]):
要求:约束与underflow()相同,不同之处在于结果字符从挂起序列传输到备份序列,并且挂接序列在传输前不得为空。
默认行为:调用underflow()。如果underflow()返回traits :: eof(),则返回traits :: eof()。否则,返回traits :: to_int_type(* gptr())的值,并为输入序列增加下一个指针的值。
返回:traits :: eof()表示失败。
在C ++中,外观如下所示:
if (traits::eq_int_type(this->underflow(),traits::eof())
return traits::eof();
return *fetch_gptr_and_inc();
我们无法直接在装饰对象上调用“ 7”,因为它不可访问。
另外,我们不想获取自己的gptr(),而是想要装饰的。
但是,我们可以通过调用sgetc()
和sbumpc
间接实现此目的:
template<typename char_type,class traits_type>
typename forwarding_basic_streambuf<char_type,traits_type>::int_type
forwarding_basic_streambuf<char_type,traits_type>::uflow()
{
if (traits_type::eq_int_type(this->m_fwd->sgetc(),traits_type::eof()))
return traits_type::eof();
return this->m_fwd->sbumpc();
}