为什么友元运算符<<在某些情况下使用,而在其他情况下不使用

Why is friend operator<< used in some cases and other cases not

本文关键字:情况下 lt 其他 友元 运算符 为什么      更新时间:2023-10-16

说我有一个Complex类。

我看过

friend ostream& operator<<( ostream& stream, Complex z)(即朋友函数)

ostream& operator<<( ostream& stream, Complex z)(即成员函数)

用过,我很难看看何时应该排除朋友,而包括朋友则被认为很重要。

我的理解:成员函数和朋友函数都可以访问Complex类的私人成员,朋友函数只能在类本身中定义,并且它还可以访问其他类的私人成员(和公共),成员函数没有。

另一个问题,因为ostream& operator<<( ostream& stream, Complex z)是成员函数,为什么不必在类本身中声明它?我认为所有成员功能都必须在类中声明?

您可以以这两种方式实现操作员超载,如果您不需要用隐式转换为Complex类型调用它,您可以使用成员函数。但是有缺点,并且通过免费功能提供friend如果需要访问私人成员,则已成为标准方式。这里最好的参考是Scott Meyer关于免费功能如何改善封装的文章。他对成员与非会员功能的建议明确包括operator <<

if (f needs to be virtual)  
   make f a member function of C;  
else if (f is operator>> or  operator<<)  
{  
   make f a non-member function;  
   if (f needs access to non-public members of C)  
      make f a friend of C;  
}
else if (f needs type conversions on its left-most argument)  
{  
   make f a non-member function;  
   if (f needs access to non-public members of C)  
      make f a friend of C;  
}  
else if (f can be implemented via C's public interface)  
   make f a non-member function;  
else  
   make f a member function of C;  

首先,

由于 ostream& operator<<( ostream& stream, Complex z)是成员函数,为什么不必在课程中声明它?

因为它不是成员函数。同类内部使用friend关键字声明的函数也不是。

朋友函数只能在课程本身中定义,并且它还可以访问其他类的私人成员(和公共),成员函数不会

成员功能在访问权利方面绝不是非会员功能。相反的事实 - 例如,成员函数可以访问其班级朋友的私人成员,非会员(甚至friend)函数都不会。

到您的原始问题:如果需要,则使用friend,因为它的作用。别无其他。

首先,朋友函数在类本身中未定义。朋友函数的定义与课堂外的任何其他功能一样定义。仅在班级中与 friend 关键字一起发表声明。

我将解释为什么需要以一种易于理解的方式将朋友用于某些操作员超载:

您已经知道,当对象调用其类成员函数时,该函数知道该对象的成员变量值是什么,并且可以自动与这些变量一起使用。您不必在功能中明确包含对象作为参数。

类似地,当您将操作员重载函数定义为成员函数时,该函数已经知道调用该函数的对象。现在让我们考虑您的示例:

friend ostream& operator<<( ostream& stream, Complex z) 

考虑如何调用此功能:

Complex z;
cout << z;

编译器看到此表达式时,它会调用非会员函数操作员&lt;&lt;与呼叫

operator<<(cout, z)

如果要将此功能声明为:

ostream& operator<<( ostream& stream, Complex z) 

这不是成员函数。成员函数将如下:

ostream& operator<<(ostream& stream)

你为什么要问?因为该函数已经知道有关对象调用此函数的所有信息。因此,它只需要了解COUT。

请记住,只有当左操作数是函数为成员的类的对象时,二进制运算符的运算符过载函数才能成为成员函数。现在考虑如何调用此功能。由于二进制运算符超载要求左操作数是定义函数的类的对象

z << cout

这将导致编译器调用,例如:

z.operator<<(cout)

但是,不使用C 程序员来语句,例如 z&lt;&lt;cout 和这样的语句只会导致混乱。每个人都期望 cout&lt;&lt;z ,但是由于您超载运算符&lt;&lt;作为会员函数,您将必须拨打 z&lt;&lt;cout 。因此,对于此类操作员,非成员的朋友功能是首选。还请记住,某些运算符,例如(),[], ->或任何作业操作员,只能将其重载为成员函数。

希望您了解为什么在某些情况下更好地使用朋友。

关于您的第二个问题:

另一个问题,因为Ostream&amp;运算符&lt;&lt;(ostream&amp; stream,复杂z)是成员函数,为什么不必在类本身中声明它?我认为所有成员功能都必须在班上声明?

所有成员功能都必须在类中声明。您可能会混淆声明和定义。定义可以在课堂内或外部,但是声明必须在课堂内。还有,

朋友函数只能在类本身中定义,并且它还可以访问其他类的私人成员(和公共),而成员函数不具有。

这是错误的。同类的朋友功能和非静态成员功能都可以访问该类的私人和公共成员变量。只有静态成员函数无法访问类的非静态成员变量。

1.朋友流&lt;&lt;意味着全球流操作员可以访问复杂的成员。对于以下exmaple,在main()中,Globle Outpream可以直接访问复杂成员。

int main(int ac, char** av)
{
    Complex complex;
    std::cout << complex;
    return 0;
}

2.成员函数&lt;&lt;复杂的意思是复杂本身是流,它可以接受类型是复杂的参数。对于以下示例:

int main(int ac, char** av)
{
    Complex comp1, comp2;
    comp1 << comp2;
    return 0;
}

即使是thogh的使用情况,它是刻板的。