C++的I/O(vc版)(三)

本文深入剖析C++中basic_ios<>类的设计原理,重点介绍字符特性和流缓冲区的概念及其在流类中的应用。

  前面已经分析完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的成员,只是我们需要考虑的是:缓冲类;具体的考虑在代码中已经很清楚了。


我们的基本的流类已经完成了,对于特定的流类,只需要加上特定的操作或数据成员即可。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值