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

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


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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个判断五子棋是否胜利,包括黑棋禁手的 C++ 代码,使用 Visual C++ 编译器进行编译测试: ```cpp #include <iostream> #include <cstring> using namespace std; const int SIZE = 15; int board[SIZE][SIZE] = {0}; // 初始化棋盘为全空 int player = 1; // 当前玩家,1为黑棋,2为白棋 bool blackForbidden = false; // 是否出现黑棋禁手 // 判断在(x,y)位置放棋子后是否有五子连珠 bool checkWin(int x, int y) { int count1 = 0, count2 = 0, count3 = 0, count4 = 0; for (int i = 0; i < 5; i++) { if (x + i < SIZE && board[x + i][y] == player) count1++; else break; } for (int i = 1; i < 5; i++) { if (x - i >= 0 && board[x - i][y] == player) count1++; else break; } for (int i = 0; i < 5; i++) { if (y + i < SIZE && board[x][y + i] == player) count2++; else break; } for (int i = 1; i < 5; i++) { if (y - i >= 0 && board[x][y - i] == player) count2++; else break; } for (int i = 0; i < 5; i++) { if (x + i < SIZE && y + i < SIZE && board[x + i][y + i] == player) count3++; else break; } for (int i = 1; i < 5; i++) { if (x - i >= 0 && y - i >= 0 && board[x - i][y - i] == player) count3++; else break; } for (int i = 0; i < 5; i++) { if (x + i < SIZE && y - i >= 0 && board[x + i][y - i] == player) count4++; else break; } for (int i = 1; i < 5; i++) { if (x - i >= 0 && y + i < SIZE && board[x - i][y + i] == player) count4++; else break; } if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5) return true; return false; } // 判断在(x,y)位置放棋子是否出现黑棋禁手 bool checkForbidden(int x, int y) { if (player == 2) return false; // 白棋没有禁手 if (board[x][y] != 1) return false; // 只有黑棋才可能出现禁手 for (int i = x - 2; i <= x + 2; i++) { for (int j = y - 2; j <= y + 2; j++) { if (i >= 0 && i + 4 < SIZE && j >= 0 && j + 4 < SIZE) { int count1 = 0, count2 = 0, count3 = 0, count4 = 0; for (int k = 0; k < 5; k++) { if (board[i + k][j] == 1) count1++; if (board[i][j + k] == 1) count2++; if (board[i + k][j + k] == 1) count3++; if (board[i + k][j - k] == 1) count4++; } if (count1 == 4 || count2 == 4 || count3 == 4 || count4 == 4) { bool hasEmpty = false, hasWhite = false; for (int k = 0; k < 5; k++) { if (board[i + k][j] == 0) hasEmpty = true; if (board[i + k][j] == 2) hasWhite = true; if (board[i][j + k] == 0) hasEmpty = true; if (board[i][j + k] == 2) hasWhite = true; if (board[i + k][j + k] == 0) hasEmpty = true; if (board[i + k][j + k] == 2) hasWhite = true; if (board[i + k][j - k] == 0) hasEmpty = true; if (board[i + k][j - k] == 2) hasWhite = true; } if (!hasEmpty || hasWhite) { blackForbidden = true; return true; } } } } } return false; } // 显示棋盘 void display() { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (board[i][j] == 0) cout << "."; else if (board[i][j] == 1) cout << "X"; else cout << "O"; } cout << endl; } cout << endl; } int main() { while (true) { display(); int x, y; cout << "Player " << player << "'s turn: "; cin >> x >> y; if (board[x][y] != 0) { cout << "Invalid move, try again.\n"; continue; } board[x][y] = player; if (checkWin(x, y)) { cout << "Player " << player << " wins!\n"; break; } if (checkForbidden(x, y)) { cout << "Black has a forbidden hand!\n"; continue; } player = 3 - player; // 切换玩家 } return 0; } ``` 这个程序使用一个二维数组 `board` 来表示棋盘,玩家1和玩家2分别用数字1和2表示。每次玩家落子时,程序会先判断该位置是否已经有棋子,如果已经有则提示无效,让玩家重新输入。然后程序会判断该位置是否出现五子连珠,如果有,则该玩家获胜。如果该位置出现黑棋禁手,则程序会提示禁手并让黑棋玩家重新输入。程序会不断循环让两个玩家落子,直到有一方胜利。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值