C ++成为好友还是不成为好友


19

我在大学这个学期的C ++课程中有一个面向对象的编程,我们正在学习有关朋友函数的知识。

我本能地讨厌它们绕过封装和数据隐藏所提供的安全性的能力,我在互联网上读了几篇文章,有些人认为这是一个合法使用的好主意。

OOP专家会对C ++中的好友功能怎么说?我应该浏览一下还是应该了解更多?


@all:很棒的答案和评论,这是一种很棒的学习方法,我不可能在教科书中了解到如此详细的朋友。
nikhil 2011年

Answers:


13

使与该类的C ++类成员相关的所有功能并不总是很方便。例如,想象一下带有标量乘法的矢量代数的实现。我们要写:

 double a;
 Vector v, w;
 w = v * a;

我们可以使用成员函数来做到这一点:

public class Vector {
 ...
 Vector operator*(double a);
}

但是我们还要写:

w = a * v

这需要一个免费功能:

 Vector operator*(double a, Vector v)

friend关键字加入到C ++来支持这种用法。free函数是Vector类实现的一部分,应在同一标头中声明,并在同一源文件中实现。

类似地,我们可以friend用来简化紧密耦合类的实现,例如集合和迭代器。同样,我将在同一标头中声明两个类,并在同一源文件中实现它们。


3
“这需要一个自由功能”。不,不是:inline Vector operator*(double a, Vector v) { return v*a; }。实际上是规范的解决方案。
MSalters 2011年

1
@MSalters:好点。我选了一个不好的例子。我认为您的内联函数从定义上来说是一个自由函数,但是不需要朋友声明。
凯文·克莱恩

4
@MSalters:仅当*是相对于a和v(x)的交换性时,才有效。如果矢量分量是通用的(不一定是标量),则必须保持操作数顺序
Emilio Garavaglia 2015年

这是很理论的。也许唯一的常见的非交换情况就是 inline Vector operator*(double a, Vector v) { return -v*a; }并且仍然不需要友谊。
MSalters 2015年

16

在封装方面,Friend函数与成员函数没有什么不同。但是,它们可以提供其他优点-例如更通用,尤其是在涉及模板的情况下。另外,只能将某些运算符指定为自由函数,因此,如果希望它们具有成员访问权限,则必须friend

相对于friend被迫制作您不想公开的功能,单个功能要好。这意味着整个世界都可以使用它,而不仅仅是一个功能。


朋友功能的 +1 与成员功能在封装方面没有什么不同。不过,这仅适用于公共成员职能。
TheFogger 2011年

1
@TheFogger:可以说,您也可以使用friend一个也是“私有”的函数,例如仅在单个TU中声明的函数。
DeadMG 2011年

5

如果您对自己的工作充满热情,那么您将学习有关C ++的所有知识。了解它们的用途,用法,然后-直到那时-决定不使用它们。至少,在阅读使用C ++这一方面的其他人的代码时,您将做好准备。


5

OOPs专家会说什么…… ”这主要取决于他在C ++中的专业程度,按照其自己的规范,该专家不是(也不想成为)纯粹主义者的语言。

OOP狂热者不使用C ++(他们更喜欢Smalltalk,并且喜欢Java)。

函数式编程Zelot不使用C ++(他们更喜欢LISP及其后续产品)

大多数OOP专家不喜欢朋友功能仅仅是因为他们希望C ++的OOP部分表现得像Smalltalk。但是C ++并不是Smalltalk,他们甚至无法理解,朋友不会破坏封装,这是非常简单的原因,即没有您的类需要它函数就不能成为您的类的朋友

并从“功能”立点之间,a.fn(b)fn(a,b)没有什么区别(这里fn是朋友):当事人是相同的。简而言之,一种语法可能比另一种语法更合适:如果fn关于a和可以互换bfn(a,b)则可能更适合a.fn(b)(其中看起来具有“特殊作用”,而实际上不适合)。


1
喜欢Java的“ OOP狂热者”不了解OOP。吸气剂?二传手?没有简单的闭包语法?用艾伦·凯(Alan Kay)来解释,这不是他想象的OOP。
康拉德·鲁道夫

@Konrad:狂热者是无限制的。始终有一个狂热者比给定的狂热者更多。
Emilio Garavaglia 2011年

我不得不说我赞成,因为我非常喜欢最后一段。很有道理。
julealgon


2

C ++ FAQ简洁:

如果可以,请使用成员,如果需要,请使用朋友。

常见问题解答提供了一种思考友谊的更有用的方法:

许多人认为朋友功能是课堂之外的东西。相反,请尝试将朋友功能视为类的公共接口的一部分。类声明中的friend函数不会违反封装,就像public成员函数违反封装一样:就访问类的非公共部分而言,两者都具有完全相同的权限。

朋友功能的最常见用法是为I / O重载<<。


0

Friend函数最适合用于用户定义的运算符定义。它们在其他情况下很有用,但是如果您发现自己经常指定朋友类,那么您可能会绕道设计(只是在编写代码时进行一次很好的自检)。

请注意原始问题中的“安全性”声明。可以使用访问修饰符来防止您意外地编写错误的代码,就像在某种程度上像编译器一样。访问修饰符限制了接口,并用于传达哪些功能对于使用该类很重要(公共的和受保护的),以及哪些功能是在使该类对维护者更漂亮的(私有的)中创建的。修饰符不构成安全性,因为有很多方法可以获取私有数据。例如,获取指向类及其大小的指针,然后钓鱼。


-2

C ++朋友功能与以下功能密切相关:

  1. 自由功能
  2. 静态功能
  3. 朋友功能

这意味着它们没有此指针,因此不在类/对象的范围内。另一方面,它们通常采用使它们再次属于该类的参数。这是一些示例,阐明了链接:

class B;
class A {
public:
    friend void f(A &a, B &b);
private:
    int m_a;
};
class B {
public:
   friend void f(A &a, B &b);
private:
   int m_b;
};
void f(A &a, B &b) { /* uses both A's and B's private data */ }

静态函数和朋友函数之间的唯一区别是,朋友函数可以使用多个类。

在c ++中使用友善机制需要程序员具有大约10-15年的c ++编程经验,因此一开始您应该避免使用它。它的高级功能。


7
而您得出的10-15年如何?
DeadMG 2011年

从第一次实际需要时起,需要10到15年的时间。
tp1

3
因此,您随便编了一个数字。
DeadMG 2011年

3
-1:“您应该避免它。” 创建C ++的每个功能都是为了解决问题。出现此问题时,请使用适当的功能。
凯文·克莱恩

感谢-1。该评论是有原因的。猜测并非所有功能都适合初学者是一个很难的概念。
tp1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.