友元,以及为什么operator<<需要被声明为友元

1.友元

  • 如果你想直接看输出运算符重载,可以直接跳过前面这一部分

1.1什么是友元

  • 友元就是声明一个函数或者类 F , 该类 F 可以随意访问你自己类中的任何成员.
  • 友元是单向的, 比如有 AB ,将 B 作为 A 的友元类. 注意,这里的 A 是主体, BA 的一个友元. 这个时候, B可以随意访问 A , 而 A 并不能随意访问 B
  • 友元是不具备传递性的. 比如(依旧使用上面的 AB ):BA 的友元,我们再加入一个 C , CB 的友元,那 C 就可以随意看 B 的内容,但是此时的 C 并不能随意的看 A 的内容(虽然 B 可以随意看 A 的内容)

1.2友元函数

  • 友元函数是将一个类的外部函数(外部函数表示不是该类里面声明的函数),通过在类的内部添加一个friend修饰的函数声明,就可以让该函数成为该类的成员函数,外部函数就可以直接访问类对象的私有变量
void fun(test a)//外部对函数进行实现,访问是需要传入友元类的对象
{
   cout << "val is" << a.val <<endl; // 可以直接访问test类对象中私有成员变量
}
class test
{
   friend void fun();//一般只在类中添加友元函数的声明,而不做实现
private: //这里是私有的
   int val;
}

1.3友元类

  • 友元类和友元方法一致,只不过这里操作的对象有一个函数变为一个类了,依旧是使用friend修饰,下面是一个例子
class B
{
	void fun(A a)//需要通过友元类的对象进行访问
	{
		cout << "val is" << a.val << endl;
	}
};
class A
{
	friend class B;
private:
	int val;
};

=============================================================================

2.operator<<

  • 在讨论之前,我们先要知道,在C++中的运算符,可以算作是一个函数名,这个函数有多重的重载方法,有丰富的使用方式。
  • 1.首先,我们在使用 cout << 输出的时候,到底发生了什么。
    • 在一开始,cout方法调用了一个方法,叫做operator<< 。该方法接收的 第一个参数 是输出流对象ostream第二个参数 才是我们想要输出的对象。我们通过该输出流对象,想标准输出所需要输出的内容。
    • cout在传参的时候,就会默认传递自身,也就是ostream。注意,强调一下,这里是第一个参数,一定要牢记,这是第一个参数。谁调用operator所对应的运算符,谁就有权力传递第一个参数。
    • 重头戏来了,我们为了使用<<运算符重载将我们的自定义对象按照合理的格式输出,我们势必需要传递一个this指针,这个是跑不了的,但是通过 对象 调用<<运算符重载的时候,this指针又会去抢占第一个参数的位置,此时的调用方法是这样的(通过对象调用):
      A << cout 。这里写的是没有问题的,如果你不将<<设置为友元,就需要这样调用,也只能这样调用。因为谁在<<之前,调用<<,谁就具有传递第一个参数的权利。
    • 为了证明我说的是对的,我写了一个例子,证明可以像 A << cout 这种形式进行输出,你大可将该代码放入你的编译器试试~~
#include<iostream>
using namespace std;
class data
{
public:
   void operator<<(ostream&out)
   {
   	cout << "hello operator <<" << endl;
   }

};
int main()
{
   data A;
   A << cout;//这不就是上面的输出方式嘛,最终会正常显示,毫无问题,
             //除了使用起来不太美观~~ 像极了 输入cin的使用,hhh 
             //这里的实际展开的是  void operator<<(*this,ostream&cout)
             //看到了吗, this已经偷偷的被加到了第一个参数的位置
   return 0;
}
  • 2.我们该如何做
    • 为了避免两者互相抢占第一个参数位置的情况,并且满足我们日常使用习惯,我们可以将该<<运算符重载为全局函数,这样,对象调用全局函数的时候,就不会传递this指针了(this指针只会在调用自己类的成员函数的时候才会传递)。
    • 但是这个时候,虽然可以正常传参了,对象会被当做第二个参数传递进去,但是如果我们需要输出类对象的私有成员变量时,又不能正常输出,因为非类的内部成员不能访问啊~~。
    • 这个时候,我们加入友元,friend,将该全局方法声明为类的友元方法,这样,就可以对类的私有成员进行随意的访问了。
    • 我们的目的达到了~~,我们可以按照正常的操作逻辑来调用<<运算符了
    • 下面的代码才是咋们想要的代码,你可以拷贝到你的编译器里试试看,多看几次,多想想两个参数的位置,就能想清楚了

如果您觉得有帮助到您的话,不妨给我点个赞 😃,谢谢,虽然点赞没啥用,但能够让我感受到帮助到您而感到十分开心 😃,如果您有问题,可以评论告诉我~~

#include<iostream>
using namespace std;
 class data
{
public:
   data() : key(10)
   {}
private:
   friend void operator<<(ostream&out, data& tmp);
   int key;
};
void operator<<(ostream&out, data& tmp)
{
   cout << "hello operator <<" << endl;
   cout << tmp.key << endl;
}
int main()
{
   data A;
   cout << A;
   system("pause");
   return 0;
}
  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值