C++输入输出操作符重载

1. 输入输出操作符简介

C++中输入操作符是>>,输出操作符是<<,又叫做流对象的“插入操作符”和“提取操作符“。其实这两个操作符最初是在C语言中用于整数的移位运算,到了C++中才利用操作符重载的技术将它们应用于输入、输出操作。

2.重载的原因

应用于基本类型的输入、输出操作都已经在C++标准库中定义好,没有必要重新定义,也不允许重新定义。而对于用户自定义类来说,如果想利用输入、输出操作符进行本类对象的输入、输出操作,就需要对<<和>>操作符进行重载。

3.重载的形式

对输出操作<<进行重载,只能采用友元函数的形式进行,而不能将operator<<()申明为ostream类的成员函数。这是因为ostream是在C++标准中定义的类,不允许用户随便修改。所以,要将类someClass的对象输出到标准输出对象,只能采用将operator<<()重载为全局函数,申明为someClass类的友元的形式进行。而且,这时的输出操作符函数原型下述五种形式之一:

ostream& operator<<(ostream&,const someClass&);
或者
ostream& operator<<(ostream&,const someClass*);

ostream& operator<<(ostream&, someClass&);
或者
ostream& operator<<(ostream&, someClass*);

ostream& operator<<(ostream&, someClass);

其一,第一种形式最好,也是最常用的。这种函数重载,既安全又高效。

对于输入操作符>>进行重载,也是能采用友元函数的形式进行,而不能讲operator>>()申明为istream类的成员函数。这是因为istream也是C++标准库的类,也不能被用户随意修改。所以,要从标准输入对象将数据读入类someClass的对象中,只能采用operator>>()重载为全局函数,且申明为someClass类的友元的形式。输入操作符函数原型一定是:

istream& ostream>>(istream&,someClass&);
或者
istream& ostream>>(istream&,someClass*);

4.重载的示例

下面是输入和、输出操作符的例子。

#include <iostream>
using namespace std;

class Complex{
    double real;
    double image;
public:
    Complex(double r=0.0,double i=0.0){
        real=r;
        image=i;
    }
    friend ostream& operator<<(ostream&,const Complex&);
    friend istream& operator>>(istream&,Complex&);
};

ostream& operator<<(ostream& o,const Complex& c){
    o<<c.real<<"+"<<c.image<<"i";
    return o;
}

istream& operator>>(istream& i,Complex& c){
    bool success=false;
    char ch;
    while(!success){
        cout<<"please input a complex:"<<endl;
        i>>c.real;
        i>>ch;
        if(ch!='+'){
            //cin.clear();          //清除错误标志
            //cin.ignore(numeric_limits<std::streamsize>::max(),'\n'); //清除缓冲区的当前行
            continue;
        }
        i>>c.image;
        i>>ch;
        if(ch!='i'){
            //cin.clear();         //清除错误标志
            //cin.ignore(numeric_limits<std::streamsize>::max(),'\n'); //清除缓冲区的当前行
            continue;
        }
        else 
            success=true;
    }
    return i;
}

int main(int argc, char* argv[])
{
    Complex c;
    cin>>c;
    cout<<c;
    return 0;
}

从键盘键入3.4+5.6i然后回车,程序的运行结果是: please input a complex: 3.4+5.6i 3.4+5.6i

阅读以上程序,要注意以下几点。 (1)对于输入输出操作符进行重载,只能采用友元函数的形式,而不能采用成员函数的形式,原因前面已经讲述。

(2)如果将输入操作符函数申明为: ostream operator<<(ostream,const Complex&); 或者将输入操作符申明为: istream operator>>(istream,Complex&); 都会产生编译错误。原因是istream类和ostream类的拷贝构造函数被申明为私有(private)成员,这样实际上就阻止了istream类型和ostream类型的参数的传值行为,也就阻止了他们成为函数的返回值。

(3)格式化的输出操作比较容易实现,因为输出的内容已经准备好,如何输出完全由程员来安排。而格式化的输入操作要复杂一些,因为输入的内容事先是不知道的,用户在输入数据的过程中可能会存在违反约定的行为。所以,在格式化输入函数中通常还要加入一些容错的处理。

在上面的程序中,对用户输入的内容的错误性判断还不是特别完善,有兴趣的读者可以自行改进或将程序中continue语句前的两行注释取消,可提高输入的容错性。关于cin的详细用法见我的另一篇blog cin的详细用法


参考文献

[1]陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008[4.7(P320-P322)]

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏积累沉淀

Java类加载原理机制

1.类的加载过程 JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize)链接又分为三个步骤,如下图所示: ? 1...

25610
来自专栏我是攻城师

关于Java里面的字符串常量池的介绍和优化

上一篇文章提到我们在java里面不是通过new创建的string字符串会被放到一个叫字符串常量池的地方,那么本篇文章我们就来详细的了解下常量池的相关知识。

1324
来自专栏Python小屋

Python编写只允许实例化一个对象的类

>>> class T: __total = 0 def __init__(self, value): if T.__total != 0: r...

3378
来自专栏mukekeheart的iOS之旅

《JavaScript高级程序设计》学习笔记(3)——变量、作用域和内存问题

欢迎关注本人的微信公众号“前端小填填”,专注前端技术的基础和项目开发的学习。 本节内容对应《JavaScript高级程序设计》的第四章内容。 1、函数:通过函数...

2906
来自专栏余林丰

初识Java反射

要详细的了解Java反射,就得要了解Java的类加载以及何为运行时动态加载等等概念。本文抛开其余概念,简单介绍Java反射,详细介绍会在以后有一个系统而全面的认...

25410
来自专栏WD学习记录

牛客网 python (1)

1. python my.py v1 v2 命令运行脚本,通过 from sys import argv如何获得v2的参数值? 

1841
来自专栏Crossin的编程教室

​Python 3 新特性:类型注解

我们知道 Python 是一种动态语言,变量以及函数的参数是不区分类型。因此我们定义函数只需要这样写就可以了:

2612
来自专栏用户3030674的专栏

java单例模式

单例设计模式:解决一个类在内存中只存在一个对象  多用于环境变量设置等  单例模式的要求:1.只能有一个对象,禁止其他程序建立该类对象          2....

781
来自专栏我是业余自学C/C++的

二维变长数组

1445
来自专栏黑泽君的专栏

打印println()方法的逻辑

892

扫码关注云+社区

领取腾讯云代金券