C++类与对象笔记十二:运算符重载二:左移运算符重载

左移运算符重载:可以打印输出自定义数据类型

为了输出重载,我们先看看现有的输出函数。输出类型为std下的ostream类型的引用。

标准输出流(全局只能有一个)。

返回值类型为ostream,函数名称operator<<,输入参数为我们自定义类型。

仿照加号运算符重载,我们先试试成员函数。

ostream& operator<<(Person& p) {}

利用成员函数重载 左移运算符调用情形:p.operator<<(p)。先有一个对象调用函数,然后还要输入一个对象。这不是我们期望的:cout << p;的情景。简写方式只能通过p << cout方式调用。

我们把cout也加入进去:返回一个ostream类型,这样可以形成链式编程。

ostream& operator<<(ostream& cout)
{
	cout << "这个对象的m_A的值为:" << this->m_A << "这个对象的m_B的值为:" << this->m_B;
	return cout;
}

这样成员函数的输入是一个ostream流的引用,输出也是一个ostream流的引用,可以满足链式需求。

调用情况:

Person p(11, 22);
// 直接调用:
//p.operator<<(cout) << endl;
// 返回类型:调用方式一。
//ostream& out = p.operator<<(cout) << endl;
// 支持这种调用。
//p << cout << endl;

输出:

这个对象的m_A的值为:11。 这个对象的m_B的值为:22

代码:

#include<iostream>
using namespace std;
#include<string>

class Person
{
public:
	Person(int a, int b)
	{
		this->m_A = a;
		this->m_B = b;
	}
	ostream& operator<<(ostream& outStream)
	{
		outStream << "这个对象的m_A的值为:" << this->m_A << "。 这个对象的m_B的值为:" << this->m_B;
		return outStream;
	}

public:
	int m_A;
	int m_B;
};

void test01()
{
	Person p(11, 22);
	// 直接调用:
	//p.operator<<(cout) << endl;
	// 返回类型:
	//ostream& out = p.operator<<(cout) << endl;
	// 支持这种调用。
	p << cout << endl;
}
int main()
{
	test01();

	system("pause");
	return 0;
}



调用方式是:p<< cout。方向反了,我们希望的场景是:cout << p;

利用成员函数实现这样的场景不行了。只能采用全局函数的形式。

一般不会利用成员函数重载左移运算符<< ,因为无法实现cout在左侧的情况。只能用全局函数来实现。

简写方式是cout << p;所以应该是cout在左,在前,p在右,在后。定义一个全局函数:

void operator<<(cout, Person p) {} // 本质:operator<<(cout, p)简化形式可以写成cout << p; 

本质:operator(cout, p),可简化写为:cout << p;

上面我们查到cout的类型为ostream;然后为了保证cout的全局唯一性:我们输入cout的引用。

补充函数:

void operator<<(ostream& cout, Person p)  // 本质:operator<<(cout, p)简化形式可以写成cout << p; 
{
	cout << "m_A = " << p.m_A << "; m_B = " << p.m_B;
}

此时可调用如下:

void test02()
{
	Person p(11, 22);
	operator<<(cout, p);
	//cout << p;
}

简化调用没问题。本质调用operator<< 也没问题。

但是cout支持链式编程,即可以在后面不断接<<,所以应该返回对于cout本体的引用

全局函数变更为:将局部变量名换成out也可以。

ostream& operator<<(ostream& out, Person p)  // 本质:operator<<(out, p)简化形式可以写成cout << p; 
{
	out << "m_A = " << p.m_A << "; m_B = " << p.m_B;
	return out;
}

还剩最后一个问题:

在类内:一般我们把字段设置为私有private。这样在类外基于全局函数的运算符重载将无法访问到字段,所以整套的做法:要把全局函数的重载声明作为友元放在类内。

#include<iostream>
using namespace std;
#include<string>

class Person
{
	friend ostream& operator<<(ostream& out, Person p);
public:
	Person(int a, int b)
	{
		this->m_A = a;
		this->m_B = b;
	}
	//ostream& operator<<(ostream& outStream)
	//{
	//	outStream << "这个对象的m_A的值为:" << this->m_A << "。 这个对象的m_B的值为:" << this->m_B;
	//	return outStream;
	//}

private:
	int m_A;
	int m_B;
};

ostream& operator<<(ostream& cout, Person p)  // 本质:operator<<(cout, p)简化形式可以写成cout << p; 
{
	cout << "m_A = " << p.m_A << "; m_B = " << p.m_B;
	return cout;
}

void test02()
{
	Person p(11, 22);
	//operator<<(cout, p) << endl;
	cout << p << endl;

}
void test01()
{
	Person p(11, 22);
	// 直接调用:
	//p.operator<<(cout) << endl;
	// 返回类型:
	//ostream& out = p.operator<<(cout) << endl;
	// 支持这种调用。
	//p << cout << endl;
}
int main()
{
	test02();

	cout;
	system("pause");
	return 0;
}

需要总结的几点:结合上一个案例加号运算符重载:发现

  • 运算符重载作为类内成员函数,在调用时是p1.operator+(p2)。可简写为p1+p2。或者p2+p1。
  • 运算符重载作为类外全局函数,在调用时是opearator(p1, p2)。可简写为p1+p2。后者p2+p1。
    • 也就是说必须类内成员函数输入参数有一个二元运算符中的一元,类外一元作为一元。
    • 类外全局函数输入参数是二元运算符中的两个元。
  • 加号无所谓方向要求。左移运算符因为有方向和顺序,所以无法用类内成员函数实现。在全局实现中也要注意参数顺序。
  • 链式编程返回本体引用。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值