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

  • Post author:
  • Post category:其他



参考:

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;
}

运行成功!


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



版权声明:本文为qq_31417941原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。