《挑战30天C++入门极限》C++的iostream标准库介绍(3)






 

C++的iostream标准库介绍(3)

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

//程序作者:管宁  
//站点:www.cndev-lab.com  
//所有稿件均有版权,如要转载,请务必著名出处和作者  
  
#include <iostream>  
using namespace std;    
    
int main()     
{    
    float pi=3.14159f;  
    cout<<pi<<endl;  
    cout.precision(2);  
    cout<<pi<<endl;  
    system("pause");    

}

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

  例如,下列程序以控制符的方式控制输出的精度:

//程序作者:管宁  
//站点:www.cndev-lab.com  
//所有稿件均有版权,如要转载,请务必著名出处和作者  
  
#include <iostream>  
#include <iomanip>  
using namespace std;    
    
int main()     
{    
    float pi=3.14159f;  
    cout<<pi<<endl;  
    cout<<setprecision(4);  
    cout<<pi<<endl;  
    system("pause");    

}

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

  对于iostream标准库来说包含了众多的成员函数,各函数都有其自身的作用,篇幅问题笔者在这里不能一一说明例举,由于标准输入对象cin提供输入的时候会自动以空格作为分界,给我们获取一行带有空格的完整字符串带来了困难,在这里补充一个非常用有的成员函数----getline()。 


  其函数原型为: 
  getlin(chiar *str,int size,char='\n'); 


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


  示例代码如下:

//程序作者:管宁  
//站点:www.cndev-lab.com  
//所有稿件均有版权,如要转载,请务必著名出处和作者  
  
#include <iostream>  
#include <iomanip>  
using namespace std;    
    
int main()     
{    
    char str[100];  
    cin.getline(str,sizeof(str),'\n');  

    cout<<str<<endl;  

    system("pause");    
}

  通过上面内容的学习,我们对i/o有了一些基本点基本的认识,现在是该切入正题的时候了,详细学习一下,如何重载左移与右移操作符。 






  先说左移(<<)操作符,也就是我们常说的输出操作符。 

  对于自定义类来说,重载左移操作符的方法我们常使用类的友元方式进行操作。
 


  示例代码如下:

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

{  
    public:  
        Test(int age = 0,char *name = "\0")  
        {  

            Test::age = age;  

            strcpy(Test::name,name);  
        }  
        void outmembers(ostream &out)  

        {  

            out<<"Age:"<<age<<endl<<"Name:"<<this->name<<endl;  
        }  
        friend ostream& operator <<(ostream& ,Test&);  
    protected:  
        int age;  

        char name[50];  
};  
ostream& operator <<(ostream& out,Test &temp)  
{  

    temp.outmembers(out);  
    return out;  

}  
int main()     
{  

    Test a(24,"管宁");  
    cout<<a;  

    system("pause");  
}

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


  重载运算符,我们知道可以是非成员方式也可以是成员方式的,对于<<来说同样也可以是成员方式,但我十分不推荐这么做,因为对于类的成员函数来说,第一个参数始终是会被隐藏的,而且一定是当前类类型的。 


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

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

{  
    public:  
        Test(int age = 0,char *name = "\0")  
        {  

            Test::age = age;  

            strcpy(Test::name,name);  
        }  
        void outmembers(ostream &out)  

        {  

            out<<"Age:"<<age<<endl<<"Name:"<<this->name<<endl;  
        }  
        ostream& operator <<(ostream &out)  
        {  
            this->outmembers(out);  
            return out;  
        }  
    protected:  
        int age;  

        char name[50];  
};  
int main()     
{  

    Test a(24,"管宁");  
    a<<cout;  

    system("pause");  
} 

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






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

  代码如下:
 

//程序作者:管宁  
//站点:www.cndev-lab.com  
//所有稿件均有版权,如要转载,请务必著名出处和作者  
#include <iostream>  
#include <fstream>  
using namespace std;    
    
class Test    
{    
    public:    
        Test(int age = 0,char *name = "\0")    
        {    

            Test::age = age;    

            strcpy(Test::name,name);    
        }    
        void outmembers(ostream &out)    

        {    

            out<<"Age:"<<age<<endl<<"Name:"<<this->name<<endl;    
        }    

        friend ostream& operator <<(ostream& ,Test&);    
    protected:    
        int age;    

        char name[50];    
};    
ostream& operator <<(ostream& out,Test &temp)    
{    

    temp.outmembers(out);    
    return out;    

}    
int main()       

{    
    Test a(24,"管宁");  
    ofstream myfile("c:\\1.txt",ios::out,0);  
    if (myfile.rdstate() == ios_base::goodbit)  
    {  

        myfile<<a;  
        cout<<"文件创建成功,写入正常!"<<endl;  
    }  

    if (myfile.rdstate() == ios_base::badbit)  

    {  
        cout<<"文件创建失败,磁盘错误!"<<endl;  
    }  

    system("pause");   
}

  对于左移运算符重载函数来说,由于不推荐使用成员方式,那么使用非成员方式在类有多重继承的情况下,就不能使用虚函数进行左移运算符重载的区分,为了达到能够区分显示的目的,给每个类分别添加不同的虚函数是必要的。 

  示例代码如下:

//程序作者:管宁    
//站点:www.cndev-lab.com    
//所有稿件均有版权,如要转载,请务必著名出处和作者    
  
#include <iostream>  
#include <fstream>  
using namespace std;    
    
class Student    
{    
    public:    
        Student(int age = 0,char *name = "\0")    
        {    

            Student::age = age;    

            strcpy(Student::name,name);    
        }    

        virtual void outmembers(ostream &out) = 0;  

        friend ostream& operator <<(ostream& ,Student&);    
    protected:    
        int age;    

        char name[50];    
};    
ostream& operator <<(ostream& out,Student &temp)    
{  

    temp.outmembers(out);    
    return out;    

}  
class Academician:public Student  
{  
    public:  
        Academician(int age = 0,char *name = "\0",char *speciality="\0"):Student(age,name)   
        {  

            strcpy(Academician::speciality,speciality);  
        }  

        virtual void outmembers(ostream &out)    

        {    

            out<<"Age:"<<age<<endl<<"Name:"<<name<<endl<<
            
"speciality:"<<speciality<<endl;    
        }  
    protected:  
        char speciality[80];  
};  
class GraduateStudent:public Academician  
{  
    public:  
        GraduateStudent(int age = 0,char *name = "\0",char *speciality="\0",
        char *investigate="\0"):Academician(age,name,speciality)  

        {  

            strcpy(GraduateStudent::investigate,investigate);  

        }  
        virtual void outmembers(ostream &out)    

        {    

            out<<"Age:"<<age<<endl<<"Name:"<<name<<endl<<
            
"speciality:"<<speciality<<endl<<"investigate:"<<investigate<<endl;    

        }  
    protected:  
        char investigate[100];  
};  
int main()  
{    

    Academician a(24,"管宁","Computer Science");  
    cout<<a;  

    GraduateStudent b(24,"严燕玲","Computer Science","GIS System");  

    cout<<b;  
    system("pause");   

}

  在上面的代码中为了能够区分输出a对象与b对象,我们用虚函数的方式重载了继承类Academician与多重继承类GraduateStudent的outmembers成员函数,由于ostream& 
operator <<(ostream& out,Student &temp) 运算符重载函数是Student基类的,Student 
&temp参数通过虚函数的定义可以适应不同派生类对象,所以在其内部调用temp.outmembers(out); 
系统可识别不同继类的outmembers()成员函数。

 

  最后看一下,右移运算符的重载,右移运算符我们也常叫它输入运算符号,对于它来说,具体实现和左移运算符的重载差别并不大,对于有多成员对象的类来说,只要保证能够完整输入各成员对象大数据就可以了。 


  示例如下:

//程序作者:管宁    
//站点:www.cndev-lab.com    
//所有稿件均有版权,如要转载,请务必著名出处和作者    
    
#include <iostream>    
using namespace std;    
    
class Test    
{    
    public:    
        Test(int age = 0,char *name = "\0")    
        {    

            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;  
        }    
        friend istream& operator >>(istream& ,Test&);    
    public:    
        int age;    

        char name[50];    
};    
istream& operator >>(istream& input,Test &temp)    
{    

    temp.inputmembers(input);    
    return input;    
}    
int main()       
{    

    Test a;    
    cin>>a;  

    cout<<a.age<<"|"<<a.name<<endl;  

    system("pause");    
}





 





 















本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端加油站

node.js 学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 ...

7210
来自专栏转行程序员

Java和Python哪个更适合初学者的问题

我个人不是很喜欢讨论这个问题,为什么呢,每个人都学习能力不一样,你要是不行,哪个对于你也不简单。

8950
来自专栏前端加油站

angular4实战(1) angular-cli

版权声明:本文为博主原创文章,未经博主允许不得转载。 ...

7420
来自专栏happyJared

this 和 super 关键字总结

this 关键字是可选的,这意味着,上面的示例可以不显式使用此关键字,但是,使用此关键字可能会使代码更易读和易懂。

10730
来自专栏happyJared

final 和 static 关键字总结

7520
来自专栏Deep learning进阶路

3-1 栈 及其 C++实现

由于栈是运算受限的线性表,所以线性表的存储结构:顺序存储 和 链式存储 都对栈适用。

11040
来自专栏大龄程序员的人工智能之路

[C++11札记]: std::function

在C/C++中函数指针作为一种回调机制被广泛使用,但是函数指针在C++面向对象编程中有些不足,比如无法捕捉上下文。举个例子,使用对象的非静态成员函数作为函数指针...

14320
来自专栏呼延

Java8 接口的静态方法和默认方法

java8的接口中可以有default方法及static方法。 普通的抽象方法不可以有实现,实现此接口的类必须实现所有抽象方法。 默认方法必须有实现,实现此...

32450
来自专栏Deep learning进阶路

2-1 线性表之顺序表 及其C语言实现

④Locate(L,x):定位,对给定值x,若线性表中存在某个元素等于x,返回其索引号i;若存在多个元素等于x,返回最小的索引 i;若不存在,返回False

47030
来自专栏北风IT之路

java8实战读书笔记:数值流、Stream创建与Optional类的使用

不知大家还记不得,在介绍函数式编程接口中为了避免基础数据类型的装箱/拆箱带来的性能损耗,特意为函数式接口引入了基础数据类型的函数式编程接口,例如IntPredi...

10520

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励