前面已经分析完ios_base类了,现在来分析一下basic_ios<>类,他是依赖于字符特性的流基类,首先明确什么是字符特性?就是与字符类型有关的特性,例如填充符,文件结束符。两个字符之间如何比较大小等等诸如此类的问题:
//此处为了简洁,将许多别文件的定义搬到此文件
typedef int _Mbstatet;
typedef fpos<_Mbstatet> streampos;
typedef streampos wstreampos;
#define EOF (-1)//原本定义于stdio.h
//下面是类char_traits的定义
//不同的字符集,不同的表述,都给string和I/O带来了变数,例如面对不同的表述。enf-of-file
//值和字符比较细节不同,具体说明见《c++标准程序库》P687-689
template<class _Elem,class _Int_type>
struct _Char_traits
{ //properties of s string or stream element
/*关于char_type和int_type的说明见《c++标准程序库》P688,我们用char_type来表示字符,用char_type以外
的值表示end-of-file,例如char表示字符,int值表示结尾符,即int_type足以容纳‘end-of-file’*/
typedef _Elem char_type;
typedef _Int_type int_ype;
typedef streampos pos_type;
typedef streamoff off_type;
static int compare(const _Elem* _first1,const _Elem* _first2,size_t _count)
{//compare [_first1,_first1+_count)with [_first2,_first2+...)
for(;0<_count;--_count,++_first1,++_first2)
if(!eq(*_first1,*_first2))
return (It(*_first1,*_first2)?-1:+1);
return (0);
}
static size_t length(const _Elem* _first)
{//find length of null-terminated sequence
size_t _count;
for(_count=0;!eq(*_first,_Elem());++_first)
++_count;
return(_count);
}
static _Elem* copy(_Elem* _first1,const _Elem* _first2,size_t _count)
{//copy[_first1,_first1+_count) to [_first2,..)
//首先测试_first2有足够的空间
return(copy(_first,_first2,_count));
}
static const _Elem* find(const _Elem* _first,size_t _count,const _Elem& ch)
{//look for _ch in[_first,_first+_count)
for(;0<_count;--_count,++first)
if(eq(*_first,_ch))
return(_first);
return(0);
}
static _Elem* move(_Elem*_first1,const _Elem* _first2,size_t _count)
{
_Elem* _next=_first1;
if(_first2<_next &&_next<_first2+_count)
for(_next+=_count,_first2+=_count;0<_count;--_count)
assign(*--)next,*--_first);
else
for(;0<_count;--_count,++_next,+__first)
assign(*_next,*_first2);
return(_first1);
}
static _Elem* assign(_Elem *_first,size_t _count, _Elem _ch)
{ // assign _Count * _Ch to [_First, ...)
_Elem *_next = _first;
for (; 0 < _count; --_count, ++_next)
assign(*_next, _ch);
return (_first);
}
static void assign(_Elem& _left, const _Elem& _right)
{ // assign an element
_left = _right;
}
static bool eq(const _Elem* _left,const _Elem* _right)
{//test for element equality
return(_left==_right);
}
static bool It(const _Elem& _left,const _Elem* _right)
{//test if _left precedes _right
return(_left<_right);
}
static _Elem to_char_type(const int_type& _meta)
{//convert metacharacter to character
return(static_cast<_Elem>(_meta));
}
static int_type to_int_type(const _Elem& ch)
{//convert metacharacter to character
return (static_cast<int_type>(ch));
}
static bool eq_int_type(const int_type& _left,const int_type* _right)
{//test for metacharacter equality
return (_left==_right);
}
static int_type not_eof(const int_type& _meta)
{//如果不是eof,返回原值,如果是eof,返回任意不是eof的值
return(_meta!=eof()?static_cast<int_type>(_meta):static_cast<int_type>(!eof()));
}
static int_type eof()
{//return end_of-file metacharacter
return(static_cast<int_type>(EOF);
}
};
//下面是char_traits
template<class _Elem>
struct char_traits :public _Char_traits<_Elem,long>
{
};
//下面是char_traits<char>,char_traits<wchar_t>,char_traits<unsigned short>特化版本,unsigned short 等同于wchar_t
//特化版本中出于效率方面的考虑,copy函数使用memcpy和wmemcpy等等,这里就不写了
我们基于上述的字符特性类,给出basic_ios<>,下面是一些使用到的类型名:
typedef basic_ios<_Elem,_Traits> _Myt;
typedef basic_ostream<_Elem,_Traits> _Myos;
typedef basic_streambuf<_Elem,_Traits> _Mysb;
typedef ctype<_Elem> _Ctype;
typedef _Elem char_type;
typedef _Traits traits_type;
typedef typename _Traits::int_type int_type;
typedef typename _Traits::pos_type pos_type;
typedef typename _Traits::off_type off_type;
basic_ios<>中多了三个数据成员:
_Mysb* _mystrbuf;//pointer to stream buffer
_Myos* _tiestr;//pointer to tied output stream
_Elem _fillch;//the fill character
分别是关联的缓冲类,和关联的outstream,这样的话在流执行输入输出操作之前,outstream会先刷新自己的缓冲区。还有填充字符。
为什么把这三个数据放到basic_ios<>中呢?因为这三个数据都是与字符特性有关的数据。
多了这三个数据,我们就得把一些ios_base中的操作重载,以包容这三个数据:
template<class _Elem,class _Traits>
class basic_ios :public ios_base
{//base class for basic_istream/basic_ostream
public:
typedef basic_ios<_Elem,_Traits> _Myt;
typedef basic_ostream<_Elem,_Traits> _Myos;
typedef basic_streambuf<_Elem,_Traits> _Mysb;
typedef ctype<_Elem> _Ctype;
typedef _Elem char_type;
typedef _Traits traits_type;
typedef typename _Traits::int_type int_type;
typedef typename _Traits::pos_type pos_type;
typedef typename _Traits::off_type off_type;
private:
_Mysb* _mystrbuf;//pointer to stream buffer
_Myos* _tiestr;//pointer to tied output stream
_Elem _fillch;//the fill character
public:
explicit basic_ios(_Mysb* _strbuf)
{//construct from stream buffer pointer
init(_strbuf);
}
virtual ~basic_ios()
{
}
//iostate与io_state的不同
void clear(iostate _state=goodbit,bool _reraise=false)
{//set state ,possibly reraise exception
ios_base::clear((iostate)(_mystrbuf==0?(int)_state|(int)badbit :(int)_state),_reraise);
}
void clear(io_state _state)
{
clear((iostate)_state);
}
//只有state非good时才设置
void setstate(iostate _state,bool _reraise =false)
{
if(_state!=goodbit)
clear((iostate)((int)rdstate()|(int)_state),_reraise);
}
void setstate(io_state _state)
{
setstate((iostate)_state);
}
//从流中复制所有格式定义
_Myt& copyfmt(const _Myt& _right)
{
_tirstr=_right.tie();
_fillch=_right.fill();
ios_base::copyfmt(_right);
return(*this);
}
_Myos* tie() const
{//return tie pointer
return (_tiestr);
}
_Myos* tie(_Myos* _newtie)
{//set tie pointer
_Myos* _oldtie=_tiestr;
_tiestr=_newtie;
return(_oldtie);
}
_Mysb* rdbuf() const
{//return stream buffer pointer
return(_mystrbuf);
}
_Mysb* rdbuf(_Mysb* _strbuf)
{//set stream buffer pointer
_Mysb* _oldstrbuf=_mystrbuf;
_mystrbuf=_strbuf;
clear();//记得要清空状态
return(_oldstrbuf);
}
locale imbue(const locale& _loc)
{//set locale to argument
locale _oldlocale=ios_base::imbue(_loc);
if(rdbuf()!=0)
rdbuf->pubimbue(_loc);
return (_oldlocale);
}
_Elem fill() const
{//return fill character
return (_fillch);
}
_Elem fill(_Elem _newfill)
{//set fill character
_Elem _oldfill=_fillch;
_fillch=_newfill;
return(_oldfill);
}
char narrow(_Elem _ch,char _dflt='\0')const
{//convert _ch to byte using imbued locale
//这里跟字符特性,字符格式有关,由locale解决
const _Ctype& _Ctype_fac=_USE(getloc(),_Ctype);
return (_Ctype_fac.narrow(_ch,_dflt));
}
_Elem widen(char _byte) const
{
const _Ctype& _Ctype_fac=_USE(getloc(),_Ctype);
return (_Ctype_fac.widen(_byte));
}
void swap(_Myt& _right)
{//swap all but edbuf() with right
ios_base::swap(_right);
swap(_fillch,_right._fillch);
swap(_tiestr,_right._tiestr);
}
void set_rdbuf(_Mysb* _strbuf)
{
_mystrbuf=_strbuf;
}
protected:
void init(_Mysb* _strbuf=0,bool _lsstd=false)
{//initialize with stream buffer pointer
_Init();//initialize ios_base
_mystrbuf=_strbuf;
_tiestr=0;
_fillch=widen(' ');
if(_mystrbuf==0)
setstate(badbit);
if(_lsstd)
_Addstd(this);//specail handling for standard stream
}
basic_ios()
{
}
private:
basic_ios(const _Myt&);//not defined not allowed
_Myt& operator=(const _Myt&);
};
上述是其部分代码,主体内容跟ios_base相似,大部分函数都是调用ios_base的成员,只是我们需要考虑的是:缓冲类;具体的考虑在代码中已经很清楚了。
我们的基本的流类已经完成了,对于特定的流类,只需要加上特定的操作或数据成员即可。