概述
(十)StringStream Class
1、不要用char*版本。
2、操作和fstream一模一样
成员函数 | 意义 |
str() | 将缓冲区内容作为string返回 |
str(string) | 将string设置为缓冲区内容 |
str(“”) | 删除缓冲区 |
tellg() | 当前读取位置 |
seekg(pos) | 设置绝对读取位置 |
seekg(offset, pos) | 设置相对pos的偏移读取位置 |
|
|
tellp() | 当前写入位置 |
seekp(pos) | 绝对写入位置 |
seekp(offset, pos) | 设置相对pos的偏移写入位置 |
|
|
常数 | 意义 |
beg | 开头 |
cur | 当前位置 |
end | 结尾 |
|
|
标志 | 意义 |
in | 读取,istringstream的默认模式 |
out | 写入,ostringstream的默认模式 |
app | 写入时添加到尾部 |
ate | 读写时,读写位置移动到文件末尾 |
trunc | 将先前的文件内容移除 |
binary | 不替换特殊字符,这样可以保留其他系统文件格式。如果是二进制文件也应该用他 |
(十一)自定义IO操作符
1、output经典做法,以输出分数为例子:
inline std::ostream&operator << (std::ostream& strm, const Fraction& f)
{
strm << f.num() << “ / ” <<f.den();
return strm;
}
就一般情况而言,上面的已经足够了。但是如果要格式化输出,就会出问题。下面给出格式化输出的方法,核心思想是变化一个string,然后用iostream的方法处理string:
template <class charT, class traits>
inline
std::basic_ostream<charT , traits>&
operator << (std::basic_ostream<charT,traits>& strm, const Fraction& f)
{
std::basic_ostringstream<charT, traits> s;
s.copyfmt(strm);//复制strm的格式化标志
s.width(0);
s << f.num() << ‘/’ <<f.den();//变成string
strm << s.str();
return strm;
}
缺点就是慢。
2、input经典做法:
inline std::istream& operator >>(std::istream& strm, Fraction& f)
{
int n,d;
strm >> n;
strm.ignore();
strm >> d;
return strm;
}
就一般情况而言,上面的已经足够了。问题一样,格式化不行。同样给出全面的解法:
template <class charT, class traits>
inline
std::basic_istream<charT , traits>&
operator >> (std::basic_istream<charT,traits>& strm, Fraction& f)
{
int n,d;
strm >> n;
if(strm.peek() == ‘/’)//检查下一个字符
{
strm.ignore();
strm >> d;
}
else
{
d = 1;
}
if (d == 0)//分母不能是0,不然抛出异常
{
strm.setstate(std::ios::failbit);
return strm;
}
if(strm)
{
f = Fraction(n,d);
}
return strm;
}
缺点同样是很慢。
3、如果需要在类中使用私有成员,可以建立专门的读取函数:
class Fraction
{
public:
virtual printOn(std::ostream& strm);
virtual scanFrom(std::istream& strm);
}
inline std::istream& operator >>(std::istream& strm, Fraction& f)
{
f.scanFrom(strm);
return strm;
}
具体操作在类成员函数中进行。
4、不使用<< 和 >> ,直接进行自定义重载,利用stream的基本函数。上面的重载函数归根到底还是使用了<<和>>,这样函数自己做完了所有的工作。但是现在不用<< 和>>,这样很多工作要自己做。偷懒的方法就是使用sentry完成预备工作。
书上是用class Row来演示的,row代表文本处理的一行。重载输出函数如下:
std::ostream& operator << (std::ostream& strm,const Row& row)
{
std::ostream::sentry se(strm)
if(se)
{
strm.write(row.c_str(), row.len());
}
return strm;
}
5、自定义格式标志符
这里指的自定义格式符号,是独立于std::ios_base的格式符号之外的。所以我们要获取一个用户自定义空间,然后管理这个玩意儿。
static const int iword_index = std::ios_base::xalloc();//获取用户自定义位置
std::ostream& fraction_space(std::ostream& strm)
{
strm.iword(iword_index) = true;//设置标志位
return strm;
}
std::ostream& operator << (std::ostream& strm,const Fraction &f)
{
if (strm.iword(iword_index))//检查标志位
{
........
}
else
{
........
}
return strm;
}
copyfmt函数会复制包括iword在内的标志位。和iword一样的函数还有pword,不常用。
(十一)stream buffer
1、streambuffer是真正执行读写操作的类。你可以直接使用它来进行读写操作,速度快的与C函数有的一拼,但是烦。
2、buffer的操作和内部细节不要深究,可以学习stream bufferiterator。
3、输出缓冲区迭代器ostreambuf_iterator用法:
std::ostreambuf_iterator<char>bufWriter(std::cout);
std::stringhello(“hello world.n”);
std::copy(hello.begin(),hello.end(), bufWriter);
4、输入缓冲区迭代器。其实仔细观察可以发现他们和istream_iterator的操作很像。
istreambuf_iterator<char>inpos(cin);
istreambuf_iterator<char>endpos;//结束标志符
while(inpos !=endpos)
{
++inpos;
}
5、
输出迭代器 | |
代码 | 作用 |
ostreambuf_iterator<char> (ostream) | 针对ostream的迭代器 |
ostreambuf_iterator<char>(buffer_ptr) | 成为buffer_ptr缓冲区的迭代器 |
*iter | 返回iter |
iter = c | 调用sputc(c),缓冲区写入字符c |
++iter | 返回iter |
iter++ | 返回iter |
failed() | 判断迭代器是否可以改写 |
|
|
输入迭代器 | |
istreambuf_iterator<char>() | 结束标识符 |
istreambuf_iterator<char>(istream) | istream迭代器 |
istreambuf_itrator<char>(buffer_ptr) | 成为buffer_ptr缓冲区的迭代器 |
*iter | 返回iter |
++iter | 调用sbumpc()函数,读取下一个字符 |
iter++ | 调用sbumpc()函数,读取下一个字符 |
iter1.equal(iter2) | 判断迭代器相等 |
iter1 == iter2 | 判断迭代器相等 |
iter1 != iter2 | 判断迭代器不相等 |
6、streambuffer的自定义不要管啦,《stl源码剖析》也没有讲,不过估计也用不到,人家google代码规范都说不要用stream了。
7、直接使用stream缓冲区,很快,之前已经使用过了,典型例子:
std::cout<< std::cin.rdbuf();
最后
以上就是迷你饼干为你收集整理的【C++】《C++标准程序库》小结第十三章-stream(3)的全部内容,希望文章能够帮你解决【C++】《C++标准程序库》小结第十三章-stream(3)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复