参考:coursera C++程序设计
流插入运算符重载
问题
1. cout
是什么?
2. 为什么 <<
可以用在cout
上
3. 为什么 cout << 5 << "this"
能够成立
- 首先,
cout
是iostream
中定义的ostream
类的对象 <<
能用在cout
上是因为,在iostream
里对<<
进行了重载
cout << 5
相当于执行函数cout.operator<<(5)
cout << "this"
相当于执行函数cout.operator<<("this")
那么如何重载才能使得cout << 5 << "this"
成立?
答案就是:返回值为cout类型
ostream& ostream::operator<<(int n)
{
//输出n的代码
return *this;
}
ostream& ostream::operator<<(const char* s)
{
//输出s的代码
return *this;
}
因此,cout << 5 << "this"
实质上是执行函数:
cout.operator<<(5).operator<<("this");
自定义重载实现
如果在程序中希望对<<
运算符进行重载,使其能够输出自定义的数据,如何实现呢?
由于ostream
类型已经在iostream
中实现,所以不能作为ostream
类的成员函数重载,只能作为全局函数或友元函数重载。
例:
全局函数实现:
class CStudent{
public:
int age;
};
int main()
{
CStudent s;
s.age = 5;
cout << s << "Hello";
return 0;
}
假设输出为5Hello
,<<
重载函数怎么实现?
ostream & operator<<(ostream & o, const CStudent & s) {//此处为了节省运行时间,使用了CStudent &
o << s.age;
return o;
}
友元函数实现
假定c是complex复数类的对象,现在希望写cout << c;
就能以a+bi
的形式输出c的值,写cin >> c;
就能从键盘接受a+bi
形式的输入,并且使c.real = a, c.imag = b
主程序:
int main() {
Complex c;
int n;
cin >> c >> n;
cout << c << "," << n;
return 0;
}
程序运行结果可以如下:
输入:13.2+133i 87
输出:13.2+133i,87
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Complex {
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;
}
在本例中,real
和imag
为私有成员变量,因此只能用友元函数重载。
流提取运算符重载
在上例中,如何实现以指定形式(13.2+133i
)读取从键盘中输入的数据呢?
原理是相似的,但操作有点麻烦。
需要以字符串形式读取数据,再将real
和imag
分开并转换为double
格式。
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;
}
总结
- 运算符重载本质上都是对重载函数的调用,重载函数可分为成员函数,友元函数,全局函数。
- 由于流提取和流插入运算符的重载函数的返回值必须是
istream
或ostream
类的引用,而这两个类已经在头文件中写好,不便更改,所以用全局或友元函数重载。 - 当这两个运算符的作用对象(在本例中为
Complex
类)为自定义时,可以用全局函数、complex
类的友元函数重载。
又有一个问题
写到这里我产生了一个疑问,那能不能用Complex
的成员函数重载呢?
于是,我把<<
重载函数的friend
去掉了,改成:
ostream & operator<<( ostream & os);
又把定义改成:
ostream & Complex::operator<<( ostream & os)
{
os << real << "+" << imag << "i"; //以"a+bi"的形式输出
return os;
}
结果报错了,查了之后发现运算符重载函数对参数的顺序是有要求的,二元运算符的重载函数的参数需要与调用时保持一致。成员函数第一个参数默认为*this
,这就意味着调用时运算符左边必须为该类的对象,右边为ostream
对象。因此稍微修改主函数代码:
int main() {
Complex c;
int n;
cin >> c >> n;
//cout << c << "," << n;
c << cout;//注意,c和cout的顺序变了
return 0;
}
运行成功!
这么做只是为了验证我的想法,仅仅为了学习,实际应用中非常不建议这么做