老实说,我认为做出这样决定的唯一原因是语法便利和传统。我将通过展示两者之间的差异以及这些差异在做出决定时的重要性来解释原因。
非会员朋友功能和公共会员功能有什么区别?不多。毕竟,成员函数只是一个带有隐藏this
参数并且可以访问类的私有成员的常规函数。
// what is the difference between the two inv functions?
// --- our code ---
struct matrix1x1 { // this one is simple :P
private:
double x;
public:
//... blah blah
void inv() { x = 1/x; }
friend void inv(matrix1x1& self) { self.x = 1/self.x; }
};
matrix1x1 a;
// --- client code ---
// pretty much just this:
a.inv();
// vs this:
inv(a);
void lets_try_to_break_encapsulation(matrix1x1& thingy) {
thingy.x = 42; // oops, error. Nope, still encapsulated.
}
它们都提供相同的功能,并且绝不会改变其他功能的功能。相同的内部结构暴露于外部世界:在封装方面没有区别。其他函数绝对没有什么不同的,因为有一个友元函数可以修改私有状态。
实际上,可以将大多数具有大多数函数的类编写为非成员友元函数(虚函数和一些重载的运算符必须是成员),提供完全相同的封装量:用户不能在不修改类的情况下编写任何其他友元函数,并且没有朋友功能以外的功能可以访问私有成员。我们为什么不这样做?因为这违背了 99.99% 的 C++ 程序员的风格,并且没有什么太大的优势可以从中获得。
不同之处在于函数的性质和调用方式。作为成员函数意味着您可以从中获取指向成员函数的指针,而作为非成员函数意味着您可以获取指向它的函数指针。但这很少相关(尤其是像std::function
周围这样的通用函数包装器)。
剩下的区别是句法。D 语言的设计者决定统一整个事情,并说您可以通过传递一个类似的对象直接调用成员函数inv(a)
,并调用一个自由函数作为其第一个参数的成员,例如a.inv()
。并且没有任何类会因为这个或其他原因而突然被严重封装。1
要解决问题中的特定示例,应该inv
是成员还是非成员?对于我上面概述的熟悉性论点,我可能会使其成为成员。非风格上,它没有任何区别。
1 . 这在 C++ 中不太可能发生,因为在这一点上这将是一个突破性的变化,没有实质性的好处。举一个极端的例子,它会破坏matrix1x1
我上面写的类,因为它使两个调用都模棱两可。