我觉得我对
friend
关键字的理解有点漏洞。
我有课,
presentation
。我在代码中将它用于两个变量,present1
和present2
,我将其与==
进行比较:
if(present1==present2)
这是我如何定义运算符
==
(在class presentation
中):
bool operator==(const presentation& p) const;
但是,我被告知使用
friend
并在课堂外定义它会更好:
friend bool operator==(presentation&, presentation&);
为什么?两者有什么区别?
您的解决方案有效,但它不如
friend
方法强大。
当一个类将一个函数或另一个类声明为
friend
时,这意味着友元函数或类可以访问声明类的私有成员和受保护成员。就好像声明的实体是声明类的成员一样。
如果将
operator==()
定义为成员函数,那么就像 friend
的情况一样,成员函数可以完全访问类的成员。但因为它是一个成员函数,所以它指定单个参数,因为第一个参数隐含为 this
:类型为 presentation
(或其后代)的对象。但是,如果您将函数定义为非成员,那么您可以指定两个参数,这将使您可以灵活地比较可以使用同一函数转换为 presentation
的任意两种类型。
例如:
class presentation {
friend bool operator==(const presentation&, const presentation&);
// ...
};
class Foo : public presentation { /* ... */ };
class Bar : public presentation { /* ... */ };
bool operator==(const presentation& p1, const presentation& p2)
{
// ...
}
bool func(const Foo& f, const Bar& b, const presentation& p)
{
return (f == b || f == p );
}
最后,这提出了一个问题“为什么要声明
friend
?”。如果 operator==()
函数不需要访问 presentation
的私有成员,那么实际上最好的解决方案是使其成为非成员、非友元函数。换句话说,不要授予不需要的函数访问权限。
在第一种情况下,您的函数
operator==
是非静态类成员。因此它可以访问私有和受保护的成员变量。
在第二种情况下,运算符是外部声明的,因此应该将其定义为类的友元来访问这些成员变量。
作为方法实现的运算符,只能被调用,如果左侧表达式是类的变量(或对象的引用),则定义该运算符。
如果是
operator==
,通常您会对比较同一类的两个对象感兴趣。实施,作为一种方法可以解决您的问题。
但是想象一下,您编写了一个字符串类,并且想要一个运算符在这种情况下工作:
const char *s1 = ...
MyString s2 = ...
if(s1 == s2){...
要使表达式
s1 == s2
合法,您必须将 opetator==
定义为 MyString
类的外部函数。
bool operator==(const char *, const MyString&);
如果操作员需要访问您班级的私有成员,则它必须是您班级的好友。
对于适用于流的运算符
<<
和 >>
,您定义一个运算符,其左操作数是流实例,右操作数是您的类,因此它们不能是您类的方法。就像上面的例子一样,如果需要访问私有成员,它们必须是你的班级和朋友的外部函数。
我喜欢伯努瓦的回答(但我不能投票赞成),但我认为举一个例子来澄清它不会有什么坏处。这是我的一些货币代码(假设其他所有内容都放置正确):
// header file
friend bool operator ==(const Money, const Money); // are the two equal?
// source file
bool operator ==(const Money a1, const Money a2)
{
return a1.all_cents == a2.all_cents;
}
希望有帮助。
在这里看看这个重复的内容:should-operator-be-implemented-as-a-friend-or-as-a-member-function
需要指出的是,这个链接的问题是关于
<<
和 >>
,它们应该作为友元实现,因为这两个操作数是不同的类型。
就您而言,将其作为课程的一部分来实现是有意义的。友元技术用于(并且很有用)用于使用多种类型的情况,并且通常不适用于
==
和 !=
。