C++流插入(输出)和流提取(输入)运算符的重载

参考:coursera C++程序设计

流插入运算符重载

问题

1. cout是什么?
2. 为什么 << 可以用在cout
3. 为什么 cout << 5 << "this"能够成立

  • 首先,coutiostream中定义的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;
}

在本例中,realimag为私有成员变量,因此只能用友元函数重载。

流提取运算符重载

在上例中,如何实现以指定形式(13.2+133i)读取从键盘中输入的数据呢?
原理是相似的,但操作有点麻烦。
需要以字符串形式读取数据,再将realimag分开并转换为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;
}

总结

  • 运算符重载本质上都是对重载函数的调用,重载函数可分为成员函数友元函数全局函数
  • 由于流提取和流插入运算符的重载函数的返回值必须是istreamostream类的引用,而这两个类已经在头文件中写好,不便更改,所以用全局或友元函数重载。
  • 当这两个运算符的作用对象(在本例中为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;
}

运行成功!
这么做只是为了验证我的想法,仅仅为了学习,实际应用中非常不建议这么做

猜你喜欢

转载自blog.csdn.net/qq_31417941/article/details/84800291
今日推荐