在 C++中,左移运算符<<
可以和 cout
一起用于输出,因此也常被称为“流插入运算符”或者“输出运算符”。实际上,<<
本来没有这样的功能,之所以能和 cout 一起使用,是因为被重载了。
特别说明:本文参考了这篇博文。
cout
是 ostream
类的对象。ostream
类和 cout
都是在头文件 <iostream> 中声明的。ostream
类将<<
重载为成员函数,而且重载了多次。
例如,为了使cout << "Star War"
能够成立,ostream
类需要将<<
进行如下重载:
ostream & ostream::operator << (const char* s)
{
//输出s的代码
return * this;
}
再如,为了使cout << 5
能够成立,ostream
类还需要将<<
进行如下重载:
ostream & ostream::operator << (int n)
{
//输出n的代码
return *this;
}
重载函数的返回值类型为 ostream
的引用,并且函数返回 *this
,就使得cout << "Star War" << 5
能够成立。这是因为cout << "Star War"
这个表达式的值依然是 cout
(说得更准确一点就是 cout
的引用),所以能够和<< 5
继续进行运算。这个表达式等价于:
(cout.operator<<("Star War")).operator<<(5);
同理,cin
是 istream
类的对象,是在头文件 <iostream> 中声明的。istream
类将>>
重载为成员函数,因此 cin
才能和>>
连用以输入数据。一般也将>>
称为“流提取运算符”或者“输入运算符”。
假定 c
是 Complex
复数类的对象,现在希望写cout<<c
就能以 a+bi
的形式输出 c
的值;写cin>>c
就能从键盘接受 a+bi
形式的输入,并且使得 c.real = a
, c.imag = b
。
显然,要对<<
和>>
进行重载,程序源码如下:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Complex
{
// 没有声明public,private,protected,默认为是private.
double real,imag;
public:
Complex( double r=0, double i=0):real(r),imag(i){ };
friend ostream & operator<<(ostream & os, const Complex & c);
friend istream & operator>>(istream & is, Complex & c);
};
ostream & operator<<(ostream & os, const Complex & c)
{
os << c.real << "+" << c.imag << "i"; //以"a+bi"的形式输出
return os;
}
istream & operator>>(istream & is, Complex & c)
{
string s;
is >> s; //将"a+bi"作为字符串读入, "a+bi" 中间不能有空格
int pos = s.find("+",0);
string sTmp = s.substr(0,pos); //分离出代表实部的字符串
c.real = atof(sTmp.c_str());//atof库函数能将const char*指针指向的内容转换成 float
sTmp = s.substr(pos+1, s.length()-pos-2); //分离出代表虚部的字符串
c.imag = atof(sTmp.c_str());
return is;
}
int main()
{
Complex c;
int n;
cin >> c >> n;
cout << c << "," << n;
return 0;
}
ostream
类和 istream
类,所以只能将<<
和>>
重载为全局函数的形式。由于这两个函数需要访问 Complex
类的私有成员,因此在 Complex
类定义中将它们声明为友元。cout<<c
会被解释成operator<<(cout, c)
,因此编写operator<<
函数时,它的两个参数就不难确定了。ostream
的引用,而不能是 ostream
对象,因为 ostream
的复制构造函数是私有的,没有办法生成 ostream
参数对象。operator<<
函数的返回值类型设为 ostream &
,并且返回 os
,就能够实现<<
的连续使用,如cout << c << 5
。在本程序中,执行第 34 行的cout<<c
进入 operator<<
后,os
引用的就是 cout
,因此第 34 行就能产生输出。