我一直在阅读c++常见问题,对朋友声明很好奇。我个人从未使用过它,但我对探索这门语言很感兴趣。
使用friend的一个好例子是什么?
读了一些常见问题,我喜欢<< >>操作符重载和添加作为这些类的朋友的想法。然而,我不确定这如何不会破坏封装。什么时候这些异常可以保持在OOP的严格范围内?
我一直在阅读c++常见问题,对朋友声明很好奇。我个人从未使用过它,但我对探索这门语言很感兴趣。
使用friend的一个好例子是什么?
读了一些常见问题,我喜欢<< >>操作符重载和添加作为这些类的朋友的想法。然而,我不确定这如何不会破坏封装。什么时候这些异常可以保持在OOP的严格范围内?
当前回答
树的例子是一个很好的例子: 在一些不同的类中实现一个对象 具有继承关系。
也许您还需要它具有一个构造函数protected和force 人们用你的“朋友”工厂。
... 好吧,坦白地说,没有它你也能生活。
其他回答
当不同的类(不是从另一个类继承一个类)正在使用另一个类的私有或受保护成员时,可以使用友情。
友元函数的典型用例是 在访问私有或受保护的两个不同的类之间进行 两者的成员。
来自http://www.cplusplus.com/doc/tutorial/inheritance/。
在这个例子中,非成员方法访问类的私有成员。这个方法必须在这个类中声明为类的友元。
// friend functions
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
Rectangle() {}
Rectangle (int x, int y) : width(x), height(y) {}
int area() {return width * height;}
friend Rectangle duplicate (const Rectangle&);
};
Rectangle duplicate (const Rectangle& param)
{
Rectangle res;
res.width = param.width*2;
res.height = param.height*2;
return res;
}
int main () {
Rectangle foo;
Rectangle bar (2,3);
foo = duplicate (bar);
cout << foo.area() << '\n';
return 0;
}
在工作中,我们广泛地请朋友来测试代码。这意味着我们可以为主应用程序代码提供适当的封装和信息隐藏。但我们也可以有单独的测试代码,使用朋友来检查内部状态和数据进行测试。
可以说,我不会将friend关键字作为设计的重要组成部分。
简短的回答是:在friend确实可以改善封装时使用它。提高可读性和可用性(操作符<<和>>是典型的例子)也是一个很好的理由。
至于改进封装的例子,专门设计用于处理其他类的内部结构的类(想到了测试类)是很好的候选。
友函数和类提供对类的私有和受保护成员的直接访问,以避免在一般情况下破坏封装。大多数使用是与ostream:我们希望能够键入:
Point p;
cout << p;
但是,这可能需要访问Point的私有数据,因此我们定义了重载操作符
friend ostream& operator<<(ostream& output, const Point& p);
然而,这里有明显的封装含义。首先,现在友类或函数可以完全访问类的所有成员,甚至不属于它的需要。其次,类和友元的实现现在交织在一起,以至于类中的内部更改可以破坏友元。
如果您将好友视为类的扩展,那么从逻辑上讲,这就不是问题。但是,在这种情况下,为什么有必要首先把朋友挖出来呢?
在不破坏封装的情况下,要实现“friends”所宣称的相同目标,可以这样做:
class A
{
public:
void need_your_data(B & myBuddy)
{
myBuddy.take_this_name(name_);
}
private:
string name_;
};
class B
{
public:
void print_buddy_name(A & myBuddy)
{
myBuddy.need_your_data(*this);
}
void take_this_name(const string & name)
{
cout << name;
}
};
封装并没有被破坏,类B不能访问A中的内部实现,但结果与我们将B声明为A的朋友是一样的。 编译器将优化掉函数调用,因此这将导致与直接访问相同的指令。
我认为使用“朋友”是一个简单的捷径,有争议的好处,但一定的成本。
在构建容器并希望为该类实现迭代器时,Friend可以派上用场。