参考:
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;
}
运行成功!
这么做只是为了验证我的想法,仅仅为了学习,实际应用中非常不建议这么做