我一直在阅读c++常见问题,对朋友声明很好奇。我个人从未使用过它,但我对探索这门语言很感兴趣。

使用friend的一个好例子是什么?


读了一些常见问题,我喜欢<< >>操作符重载和添加作为这些类的朋友的想法。然而,我不确定这如何不会破坏封装。什么时候这些异常可以保持在OOP的严格范围内?


当前回答

正如朋友声明的参考资料所说:

友元声明出现在类主体中,并授予函数或另一个类对出现友元声明的类的私有和受保护成员的访问权。

所以提醒一下,有些回答中有技术错误,说朋友只能访问受保护的成员。

其他回答

您使用私有/受保护/公共权限控制成员和函数的访问权限? 所以假设这3个层面中的每一个都很清楚,那么很明显我们遗漏了一些东西……

例如,将成员/函数声明为protected是非常通用的。你的意思是,这个功能对每个人来说都是遥不可及的(当然,继承的孩子除外)。但是异常呢?每个安全系统都让你有某种类型的“白名单”,对吗?

所以,“朋友”让你拥有坚如磐石的对象隔离的灵活性,但也允许为你认为合理的事情创造一个“漏洞”。

我想人们之所以说不需要它,是因为总有一种设计可以不需要它。我认为这类似于讨论全局变量:你永远不应该使用它们,总有办法不用它们……但在现实中,你会看到在某些情况下,这是(几乎)最优雅的方式……我认为朋友之间也是如此。

它实际上没有任何好处,除了让你在不使用设置函数的情况下访问成员变量

但这并不是正确的看法。 其理念是控制WHO可以访问什么,是否有设置功能与此关系不大。

另一种用法:friend(+虚拟继承)可以用来避免从一个类派生(又名:“make a class underivable”)=> 1,2

从2:

 class Fred;

 class FredBase {
 private:
   friend class Fred;
   FredBase() { }
 };

 class Fred : private virtual FredBase {
 public:
   ...
 }; 

友函数和类提供对类的私有和受保护成员的直接访问,以避免在一般情况下破坏封装。大多数使用是与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的朋友是一样的。 编译器将优化掉函数调用,因此这将导致与直接访问相同的指令。

我认为使用“朋友”是一个简单的捷径,有争议的好处,但一定的成本。

In C++ "friend" keyword is useful in Operator overloading and Making Bridge. 1.) Friend keyword in operator overloading :Example for operator overloading is: Let say we have a class "Point" that has two float variable"x"(for x-coordinate) and "y"(for y-coordinate). Now we have to overload "<<"(extraction operator) such that if we call "cout << pointobj" then it will print x and y coordinate (where pointobj is an object of class Point). To do this we have two option: 1.Overload "operator <<()" function in "ostream" class. 2.Overload "operator<<()" function in "Point" class. Now First option is not good because if we need to overload again this operator for some different class then we have to again make change in "ostream" class. That's why second is best option. Now compiler can call "operator <<()" function:

   1.Using ostream object cout.As: cout.operator<<(Pointobj) (form ostream class).
2.Call without an object.As: operator<<(cout, Pointobj) (from Point class).

Beacause we have implemented overloading in Point class. So to call this function without an object we have to add"friend" keyword because we can call a friend function without an object. Now function declaration will be As: "friend ostream &operator<<(ostream &cout, Point &pointobj);" 2.) Friend keyword in making bridge : Suppose we have to make a function in which we have to access private member of two or more classes ( generally termed as "bridge" ) . How to do this: To access private member of a class it should be member of that class. Now to access private member of other class every class should declare that function as a friend function. For example : Suppose there are two class A and B. A function "funcBridge()" want to access private member of both classes. Then both class should declare "funcBridge()" as: friend return_type funcBridge(A &a_obj, B & b_obj);I think this would help to understand friend keyword.

我发现了一个使用好友访问的方便地方:私有函数的Unittest。