【转】C++ stringstream介绍,使用方法与例子

C++引入了ostringstreamistringstreamstringstream这三个类,要使用他们创建对象就必须包含sstream.h头文件。

istringstream类用于执行C++风格的串流输入操作。

ostringstream类用于执行C++风格的串流输出操作。

stringstream类同时可以支持C++风格的串流的输入输出操作。

istringstream类是从istream和stringstreambase派生而来,ostringstream是从ostream和 stringstreambase派生而来, stringstream则是从iostream类和stringstreambase派生而来。

他们的继承关系如下图所示:

istringstream

istringstream是由一个string对象构造而来,istringstream类从一个string对象读取字符。

其构造函数原型如下:

istringstream::istringstream(string str);

例子

 1 #include <iostream>
 2 #include <sstream>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     istringstream istr;
 8     istr.str("1 56.7");
 9     //上述两个过程可以简单写成 istringstream istr("1 56.7");
10     cout << istr.str() << endl;
11     int a;
12     float b;
13     istr >> a;
14     cout << a << endl;
15     istr >> b;
16     cout << b << endl;
17     system("pause");
18     return 0;
19 }

输出结果

上例中,构造字符串流的时候,空格会成为字符串参数的内部分界,例子中对a,b对象的输入“赋值”操作证明了这一点,字符串的空格成为了整型数据与浮点型数据的分界点,利用分界获取的方法我们事实上完成了字符串到整型对象与浮点型对象的拆分转换过程。

str()成员函数的使用可以让istringstream对象返回一个string字符串(例如本例中的输出操作(cout<<istr.str();))。

ostringstream

ostringstream同样是由一个string对象构造而来,ostringstream类向一个string插入字符。

其构造函数原型如下:

ostringstream::ostringstream(string str);

例子

 1 /**
 2 * File name: ostringstream.cpp
 3 * Date: 2017.10.11
 4 * Description:  An example of using ostringstream
 5 */
 6 #include <iostream>
 7 #include <sstream>
 8 #include <string>
 9 using namespace std;
10 
11 int main()
12 {
13     ostringstream ostr;
14     //ostr.str("abc");//如果构造的时候设置了字符串参数,那么增长操作的时候不会从结尾开始增加,而是修改原有数据,超出的部分增长
15     ostr.put('d');
16     ostr.put('e');
17     ostr << "fg";
18 
19     string gstr = ostr.str();
20     cout << gstr << endl;
21     system("pause");
22     return 0;
23 }

输出结果

在上例代码中,我们通过put()或者左移操作符可以不断向ostr插入单个字符或者是字符串,通过str()函数返回增长过后的完整字符串数据,但值得注意的一点是,当构造的时候对象内已经存在字符串数据时,则增长操作的时候不会从结尾开始增加,而是修改原有数据,超出的部分增长。

stringstream

stringstream的构造函数原型如下:

stringstream::stringstream(string str);

例子

 1 /**
 2 * File name: ostringstream.cpp
 3 * Date: 2017.10.11
 4 * Description:  An example of using ostringstream
 5 */
 6 #include <iostream>
 7 #include <sstream>
 8 #include <string>
 9 using namespace std;
10 
11 int main()
12 {
13     stringstream ostr("ccc");
14     ostr.put('d');
15     ostr.put('e');
16     ostr << "fg";
17     string gstr = ostr.str();
18     cout << gstr << endl;
19 
20     char a;
21     ostr >> a;
22     cout << a << endl;
23     system("pause");
24     return 0;
25 }

输出结果

除此以外,stringstream类的对象我们还常用它进行string与各种内置类型数据之间的转换。

例子

 1 #include <iostream>
 2 #include <sstream>
 3 #include <string>
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     stringstream sstr;
 9     //-----int转string------
10     int a = 100;
11     string str;
12     sstr << a;
13     sstr >> str;
14     cout << str << endl;
15 
16     //------string转char[]-------
17     sstr.clear();//如果你想通过使用同一stringstream对象实现多种类型的转换,请注意在每一次转换之后都必须调用clear()成员函数。
18     string name = "colinguan";
19     char cname[200];
20     sstr << name;
21     sstr >> cname;
22     cout << cname << endl;
23     system("pause");
24     return 0;
25 }

输出结果

使用stringstream对象简化类型转换

C++标准库中的<sstream>提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性、类型安全和可扩展性。在本文中,我将展示怎样使用这些库来实现安全和自动的类型转换。

为什么要学习

如果你已习惯了<stdio.h>风格的转换,也许你首先会问:为什么要花额外的经历来学习基于<sstream>的类型转换呢?也许对下面一个简单的例子的回顾能够说服你。假设你想用sprintf()函数将一个变量从int类型转换到字符串类型,为了正确地完成这个任务,你必须确保目标缓冲区有足够大空间以容纳转换完的字符串。此外,还必须使用正确的格式化符。如果使用了不正确的格式化符,会导致非预知的后果。下面是一个例子:

int n = 10000;
char s[10];
sprintf(s,"%d",n);//s中的内容为"10000"

到目前为止看起来还不错。但是,对上面代码的一个微小改动就会使程序崩溃:

int n = 10000;
char s[10];
sprintf(s,"%f",n);//看,错误的格式化符

在这种情况下,程序员错误地使用了%f格式化符替代了%d。因此,s在调用玩sprintf后包含了一个不确定的字符串。要是能自动推导出正确的类型,岂不是更好?

进入stringstream

由于n和s的类型在编译期就确定了,所以编译器拥有足够的信息来判断需要哪些转换。<sstream>库中声明的标准类就利用了这一点,自动选择所必需的转换。而且,转换结果保存在stringstream对象的内部缓冲中。你不必担心缓冲区溢出,因为这些对象会根据需要自动分配存储空间

<sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本。简单起见,主要以stringstream为中心,因为每个转换都要涉及到输入和输出操作。

注意,<sstream>使用string对象来代替字符数组。这样可以避免缓冲区溢出的危险。而且,传入参数和目标对象的类型被自动推导出来,即使使用了不正确的格式化符也没有危险

重复利用stringstream对象

如果你打算在多次转换中使用同一个stringstream对象,记住在每次转换前要使用clear()方法;

在多次转换中重复使用同一个stringstream(而不是每次都创建一个新的对象)对象最大的好处在于效率。stringstream对象的构造和析构函数通常是非常耗费CPU时间的

在类型转换中使用模板

你可以轻松地定义函数模板来将一个任意的类型转换到特定的目标类型。例如,需要将各种数字值,如int、long、double等等转换成字符串,要使用以一个string类型和一个任意值t为参数的to_string()函数。to_string()函数将t转换为字符串并写入result中。使用str()成员函数来获取流内部缓冲的一份拷贝:

template<class T>
void to_string(string & result,const T& t)
{
    ostringstream oss;//创建一个流
    oss<<t;//把值传递如流中
    result=oss.str();//获取转换后的字符转并将其写入result
}

//这样,你就可以轻松地将多种数值转换成字符串了:

to_string(s1,10.5);//double到string
to_string(s2,123);//int到string
to_string(s3,true);//bool到string

可以更进一步定义一个通用的转换模板,用于任意类型之间的转换。函数模板convert()含有两个模板参数out_type和in_value,功能是将in_value值转换成out_type类型:

template<class out_type,class in_value>
out_type convert(const in_value & t)
{
    stringstream stream;
    stream<<t;//向流中传值
    out_type result;//这里存储转换结果
    stream>>result;//向result中写入值
    return result;
}
//这样使用convert():
double d;
string salary;
string s=”12.56”;
d=convert<double>(s);//d等于12.56
salary=convert<string>(9000.0);//salary等于”9000”

结论

在过去留下来的程序代码和纯粹的C程序中,传统的<stdio.h>形式的转换伴随了我们很长的一段时间。但是,如文中所述,基于stringstream的转换拥有类型安全和不会溢出这样抢眼的特性,使我们有充足的理由抛弃<stdio.h>而是用<sstream>。

原文地址:https://www.cnblogs.com/codingmengmeng/p/7651795.html