c++ io标准库2

发布时间:2020-03-23 07:08    浏览次数 :

[返回]

/*
测试程序:
    Test a,b("winxos"),c("emath",1);
    cout<<a<<b<<c<<endl;
    a=b++;
    cout<<b<<a<<endl;
    a=++b;
    cout<<b<<a<<endl;
之前未重载赋值号时出现奇怪错误,debug模式下运行出错,release模式有结果,但是明显有问题,运行结果如下:
ID: 1's name is: null   My age is: 0  Value:0 0 0 0 0
ID: 2's name is: winxos My age is: 0  Value:0 1 2 3 4
ID: 3's name is: emath  My age is: 1  Value:0 2 4 6 8

failbit 非致命的输入/输出错误,可挽回

ID: 6 destoryed!
ID: 2's name is: winxos My age is: 2  Value:0 1 2 3 4
ID: 6's name is: winxos My age is: 2  Value:-572662307 -572662307 -572662307 -57
2662307 -572662307

  ostrstream::ostrstream(char *_Ptr,int streamsize,int Mode = ios::out);

ID: 4 destoryed!
ID: 5 destoryed!
ID: 2's name is: winxos My age is: 1  Value:0 1 2 3 4
ID: 5's name is: winxos My age is: 0  Value:-572662307 -572662307 -572662307 -57
2662307 -572662307

  下例示例,表示出了上面各成员函数的用法:

ID: 4 destoryed!
ID: 5 destoryed!
ID: 2's name is: winxos My age is: 1  Value:0 1 2 3 4
ID: 1's name is: winxos My age is: 0  Value:0 1 2 3 4

class Test
{
public:
Test(int age = 0,char *name = "")
{
Test::age = age;
strcpy(Test::name,name);
}
void inputmembers(istream &out)
{
cout<<"please input age:";
cin>>Test::age;
cout<<"please input name:";
cin>>Test::name;
}
friendistream& operator >>(istream& ,Test&);
public:
int age;
char name[50];
};
istream& operator >>(istream& input,Test &temp)
{
temp.inputmembers(input);
return input;
}
intmain()
{
Test a;
cin>>a;
cout<<a.age<<"|"<<a.name<<endl;
system("pause");
}

ID: 6 destoryed!
ID: 2's name is: winxos My age is: 2  Value:0 1 2 3 4
ID: 1's name is: winxos My age is: 2  Value:0 1 2 3 4

  istrstream类是从istream(输入流类)和strstreambase(字符串流基类)派生而来,ostrstream是从ostream(输出流类)和strstreambase(字符串流基类)派生而来,strstream则是从iostream(输入输出流类)和和strstreambase(字符串流基类)派生而来。

/*
c++ 语言运算符重载以及临时变量问题的测试程序。
winxos 2009-06-01
*/
#include <iostream>
#include <string>
using namespace std;
#define NUM_LEN 10
static int idnum=0;    //标记对象
class Test
{
public:
    Test():name("null"),age(0),id(++idnum)    //空参数构造
    {
        num=new int[NUM_LEN];
        for(int i=0;i<NUM_LEN;i++)
            num[i]=0;
    }
    Test(string n):name(n),age(0),id(++idnum)    //1个参数(姓名)的构造
    {
        num=new int[NUM_LEN];
        for(int i=0;i<NUM_LEN;i++)
            num[i]=i;
    }
    Test(string n,int a):name(n),age(a),id(++idnum)    //2个参数(姓名,年龄)的构造
    {
        num=new int[NUM_LEN];
        for(int i=0;i<NUM_LEN;i++)
            num[i]=i*2;
    }
    Test(Test &b)    //拷贝构造
    {
        num=new int[NUM_LEN];    //深拷贝
        copy(b.num,b.num+NUM_LEN,num);
        age = b.age ;
        name =b.name ;
        id=(++idnum);
    }
    ~Test()    //析构
    {
        cout<<"ID: "<<this->id <<" destoryed!"<<endl;
        delete []num;
    }
    /*
    mathe所说的:前缀重载使用X& operator++(X& x);
    我测试之后发现是否用引用似乎对结果没有影响,不知道具体有什么差别?
    */
    Test operator ++ (int) //后缀重载,注意括号内一定是一个int而且不能在变量
    {
        Test ret(*this);    //后缀返回值不变
        this->age++;
        return ret;    //编译时为何这里不会出现返回临时变量的警告呢?是否由于拷贝构造函数的存在使之等价于Test(ret)?
    }
    Test operator ++ ()    //前缀
    {
        this->age++;
        return (*this);
    }
    /*
    这里非常重要,如果未重载赋值号的话,将造成返回临时变量,会导致析构出错。尾部附有重载与未重载时的运行结果差别。
    */
    bool operator = (const Test &b) //
    {
        copy(b.num,b.num+NUM_LEN,num);
        age = b.age;
        name =b.name;
        return true;
    }
    int operator ! ()  //前缀重载,单目运算符可能无法实现后缀重载
    {
        return (this->age)*(this->age);
    }
    friend ostream& operator << (ostream &out,Test &t);//友元函数声明,函数体最好是要放到类的外部。
private:
    string name;
    int age;
    int *num;
    int id;
};
ostream& operator << (ostream &out,Test &t)    //重载输出流
{
    out<<"ID: "<<t.id<<"'s name is: "<<t.name<<"tMy age is: "<<t.age<<"  Value:";
    for (int i=0;i<5;i++)
        out<<t.num[i]<<" ";
    out<<endl;
    return out;
}
int main()
{
    Test a,b("winxos"),c("emath",1);
    cout<<a<<b<<c<<endl;
    a=b++;
    cout<<b<<a<<endl;
    a=++b;
    cout<<b<<a<<endl;
    /*
    我还想实现的重载:
    比如如何实现 int i=b;
    其中b为Test类,这个操作实现将b.age赋值给i,请问如何实现?
    */
    int i;
    i=!b;    //前缀运算没问题,如何重载能够使用 i=b!
    cout<<i<<endl;
    /*
    还有一个问题,如何重载 ** 符号?(两个乘法连在一起)
    直接照例会出现 error C2143: 语法错误 : 缺少“;”(在“*”的前面)
    */
    return 0;
}

bool good();

ID: 3 destoryed!
ID: 2 destoryed!
ID: 6 destoryed!
请按任意键继续. . .
我们可以发现执行 a=b++;后,输出a,发现a的id变成了5,说明a已经指向临时变量了,所以导致了析构出错。
重载之后结果如下:
ID: 1's name is: null   My age is: 0  Value:0 0 0 0 0
ID: 2's name is: winxos My age is: 0  Value:0 1 2 3 4
ID: 3's name is: emath  My age is: 1  Value:0 2 4 6 8

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者

ID: 3 destoryed!
ID: 2 destoryed!
ID: 1 destoryed!
请按任意键继续. . .
请按任意键继续. .
我们可以发现a的id正常
*/

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

badbit 致命的输入/输出错误,无法挽回
有两种方法可以获得输入/输出的状态信息。一种方法是通过调用rdstate()函数,它将返回当前状态的错误标记。例如,假如没有任何错误,则rdstate()会返回goodbit.

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者

  示例代码如下:

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

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

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者
#include <iostream>
#include <fstream>
usingnamespace std;

  下面的示例代码就是将上面的<<重载函数修改成成员方式的做法:

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者
#include <iostream>
#include <strstream>
usingnamespace std;
intmain()
{
char *name = "www.cndev-lab.com";
int arraysize = strlen(name)+1;
istrstream is(name,arraysize);
char temp;
is>>temp;
cout<<temp;
system("pause");
}

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者
#include <iostream>
#include <sstream>
#include <string>
usingnamespace std;

  接下来我们来学习一下输入/输出的状态标志的相关知识,C++中负责的输入/输出的系统包括了关于每一个输入/输出操作的结果的记录信息。这些当前的状态信息被包含在io_state类型的对象中。io_state是一个枚举类型(就像open_mode一样),以下便是它包含的值。

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者

  示例代码如下:

  stringstream::stringstream(string str);

#include <iostream>
usingnamespace std;

  ostringstream同样是由一个string对象构造而来,ostringstream类向一个string插入字符。
  ostringstream的构造函数原形如下:
  ostringstream::ostringstream(string str);

  从代码实现上,我们将函数修改成了ostream& operator <<(ostream &out),迫不得已将ostream类型的引用参数放到了后面,这是因为,成员方式运算符重载函数第一个参数会被隐藏,而且一定是当前类类型的,这和ostream类型冲突了。由此我们在使用cout输出的时候就必须写成a<<cout;,这样一来代码的可读行就大大降低了,这到底是左移还是右移呢?为此我再一次说明,对于左移和右移运算符的重载是十分不推荐使用成员函数的方式编写的。

  代码如下:

先说左移(<<)操作符,也就是我们常说的输出操作符
  对于自定义类来说,重载左移操作符的方法我们常使用类的友元方式进行操作。

  上例代码中,我们对void outmembers(ostream &out)的参数使用ostream定义主要是为了可以向它传递任何ostream类对象不光是cout也可以是ofstrem或者是ostrstream和ostringstream类对象,做到通用性。

  示例代码如下:

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者
#include <iostream>
usingnamespace std;

  示例代码如下:

  示例代码如下:

intmain()
{
float pi=3.14159f;
cout<<pi<<endl;
cout<<setprecision(4);
cout<<pi<<endl;
system("pause");
}

图片 1

  2.使用C++输入输出控制符,控制符是在拖文件iomanip.h中定义的对象,与成员函数有一样的效果,控制符不必像成员函数学那样单独调用,它可以直接插入流中使用。
  例如,下列程序以控制符的方式控制输出的精度:

类istrstream的构造函数原形如下:
  istrstream::istrstream(const char *str,int size);
  参数1表示字符串数组,而参数2表示数组大小,当size为0时,表示istrstream类对象直接连接到由str所指向的内存空间并以结尾的字符串。

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者

  第一个参数是字符数组,第二个是说明数组的大小,第三个参数是指打开方式。

  下表我们列出了一些比较常用的控制符号,由于篇幅有限读者请根据自己的需要查阅相关书籍:

system("pause");
}

//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者
#include <iostream>
#include <sstream>
usingnamespace std;
intmain()
{
istringstream istr;
istr.str("1 56.7",);
//上述两个过程可以简单写成 istringstream istr("1 56.7");
cout << istr.str()<<endl;
int a;
float b;
istr>>a;
cout<<a<<endl;
istr>>b;
cout<<b<<endl;
system("pause");
}

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

char a;
ostr>>a;
cout<<a

goodbit 无错误

通常当我们发现输入有错又需要改正的时候,使用clear()更改标记为正确后,同时也需要使用get()成员函数清除输入缓冲区,以达到重复输入的目的。

intmain()
{
int a;
cin>>a;
cout<<cin.rdstate()<<endl;
if(cin.rdstate() == ios::goodbit)
{
cout<<"输入数据的类型正确,无错误!"<<endl;
}
if(cin.rdstate() == ios_base::failbit)
{
cout<<"输入数据类型错误,非致命错误,可清除输入缓冲区挽回!"<<endl;
}
system("pause");
}

#include <iostream>
usingnamespace std;

  第一个参数是字符数组,用于存放整行文本,第二个参数读取的最大字符个数,第三个参数为作为分界界限的字符,默认识是n,换行符。

  如果错误发生,那么流状态既被标记为错误,你必须清除这些错误状态,以使你的程序能正确适当地继续运行。要清除错误状态,需使用clear()函数。此函数带一个参数,它是你将要设为当前状态的标志值。,只要将ios::goodbit作为实参。

intmain()
{
int a;
cin>>a;
cout<<cin.rdstate()<<endl;
if(cin.good())
{
cout<<"输入数据的类型正确,无错误!"<<endl;
}
if(cin.fail())
{
cout<<"输入数据类型错误,非致命错误,可清除输入缓冲区挽回!"<<endl;
}
system("pause");
}

Eofbit 已到达文件尾

C语言提供了格式化输入输出的方法,C++也同样,但是C++的控制符使用起来更为简单方便,在c++下有两中方法控制格式化输入输出。
  1.有流对象的成员函数。
  例如,下列程序以成员函数的方式控制输出的精度:

为了巩固学习,下面我们以fstream对象输出为例做一个练习。

bool bad();

对于stringstream了来说,不用我多说,大家也已经知道它是用于C++风格的字符串的输入输出的。
  stringstream的构造函数原形如下:

  另一种方法则是使用下面任何一个函数来检测相应的输入/输出状态:

  代码如下:

下一篇:没有了