当朋友功能绝对优于成员功能时,任何机构都可以给我一个条件吗?或者仅仅是我们可能使用友元函数而不是成员函数的一些原因。非常感谢。
4 回答
流操作。
友元函数非常适合运算符重载。
对于像 inserter<<
或 extractor这样的运算符>>
,流对象出现在左侧,因此它不能成为成员。但是,可以说这样的函数很少会成为朋友,因为它应该建立在公共检查或初始化接口上。
二进制操作。
二元运算符,尤其是可交换运算符提供了一个更有趣的例子。如果实现为成员函数,则根据使用 LHS 的成员查找来调度重载。友元函数将使用与 LHS 和 RHS 同等对待的参数相关查找。
如果允许转换,这一点很重要。如果我有一个从C 样式字符串string
隐式转换的类,则不会找到表达式,但会找到。顺便说一句,符合这个例子,这就是它使用非成员运算符的原因。char const *
string string::operator+(string)
"x" + str
friend string operator+(string, string)
std::string
接口跨越的不仅仅是你的类。
另一种情况是当您想要一些不能成为成员的东西时,因为它是在您无法控制的类或非类类型上定义的。当应用于“随机事物”时,也许它只是一个无操作,但仍然有意义。例如,我定义了这样一个函数flush
,它表示输入结束并通过解析器传播。在我没有实现的许多事情中,含义都得到了很好的定义。
一种情况(可能是典型情况)是当您尝试重载<<
运算符以打印您的类的成员时。您根本不能将它重载为 a,member function
因为第一个参数必须是ostream
. 您必须使用该friend
功能。
根据 Scott Myers 的 Effective C++ Item23:
与成员函数相比,更喜欢非成员非朋友函数。这样做可以提高封装、封装灵活性和功能可扩展性。
面向对象设计的基石之一是对象通过发送消息进行交互。为了发送消息(在这种情况下,调用成员函数),对象必须具有到目标对象的“链接”。该链接是通过在两个类之间建立关联作为类型定义的一部分而形成的。
在对等关系中,任何一个对象都可以调用另一个对象的操作。也就是说,关系是双向的。
如果关联是双向的,那么两个类都需要指针。当您必须将对象绑定在一起时,问题就来了。问题是首先构建哪个对象?如果两个类都需要在其构造函数中引用另一个类才能工作,则存在循环依赖关系。
可能最优雅的方法是创建一个将两个对象绑定在一起的自由函数。'bind' 函数是两个类的朋友,以允许连接它们的指针(不以其他方式暴露它们):
class CameraStabiliser;
class UI
{
private:
CameraStabiliser* pStabiliser;
public:
UI() : pStabiliser(NULL) {}
void inPosition();
friend void bind(UI& ui, CameraStabiliser& cs);
};
class CameraStabiliser
{
private:
UI* pUI;
public:
CameraStabiliser() : pUI(NULL) {}
void moveTo(Position pos);
friend void bind(UI& ui, CameraStabiliser& cs);
};
void bind(UI& ui, CameraStabiliser& cs)
{
ui.pStabiliser = &cs;
cs.pUI = &ui;
}
int main()
{
UI console;
CameraStabiliser stabiliser;
bind(console, stabiliser);
}
当您重载使用来自同一类的参数的运算符时,您将使用成员函数。另外,为了定义类的行为,你使用成员函数。友元函数用于重载使用不同类参数的运算符,
例如流运算符,
cout << 2
在这种情况下,cout 是 ostream 类的对象,2 是 int 类的成员。
在这种情况下,您将使用非成员函数的友元函数,它们允许您在使用运算符时也使用其他类的对象。流插入运算符和流提取运算符就是示例。