我觉得我对friend
关键字的理解有点漏洞。
我有一个班级presentation
。我在代码中使用了两个变量present1
和present2
,我将其与==
进行比较:
if(present1==present2)
以下是我如何定义运算符==
(在class presentation
中):
bool operator==(const presentation& p) const;
但是,我被告知使用friend
并在课堂外定义它更好:
friend bool operator==(presentation&, presentation&);
为什么呢?这两者有什么区别?
答案 0 :(得分:13)
您的解决方案有效,但功能不如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
的私有成员,那么确实最好的解决方案是使其成为非成员,非朋友函数。换句话说,不要给出不需要的功能访问权限。
答案 1 :(得分:2)
在第一种情况下,您的函数operator==
是非静态类成员。因此,它可以访问私有和受保护的成员变量。
在第二种情况下,运算符是外部声明的,因此应将其定义为类的朋友以访问这些成员变量。
答案 2 :(得分:1)
我喜欢Benoit的答案(但我不能投票),但我想一个例子并不会让人明白它。这里有一些我有的Money代码(假设其他一切都是正确的):
// 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;
}
希望有所帮助。
答案 3 :(得分:0)
在这里看一下这个副本:should-operator-be-implemented-as-a-friend-or-as-a-member-function
重要的是要指出,这个关联的问题是关于<<
和>>
应该作为朋友实现,因为这两个操作数是不同的类型。
在你的情况下,将它作为课程的一部分来实现是有意义的。对于使用多种类型且通常不适用于==
和!=
的情况,使用友元技术(并且非常有用)。
答案 4 :(得分:0)
作为方法实现的运算符只能被调用,如果左侧表达式是类的变量(或对象的引用),则为运算符定义。
如果是operator==
,通常您有兴趣比较同一类的两个对象。实现,作为一种方法解决了你的问题。
但是,想象一下,你编写一个字符串类,并且你想要一个运算符,在这种情况下工作:
const char *s1 = ...
MyString s2 = ...
if(s1 == s2){...
要使表达式s1 == s2
合法,您必须将opetator==
定义为MyString
类外部的函数。
bool operator==(const char *, const MyString&);
如果您的班级需要访问私人会员,则必须是您班级的朋友。
如果运算符<<
和>>
适用于流,则定义一个运算符,其左操作数是流实例,右操作数是您的类,因此它们不能是你班级的方法。与上面的示例一样,如果需要访问私有成员,则必须是您的班级和朋友外部的功能。