我一直在阅读c++常见问题,对朋友声明很好奇。我个人从未使用过它,但我对探索这门语言很感兴趣。
使用friend的一个好例子是什么?
读了一些常见问题,我喜欢<< >>操作符重载和添加作为这些类的朋友的想法。然而,我不确定这如何不会破坏封装。什么时候这些异常可以保持在OOP的严格范围内?
我一直在阅读c++常见问题,对朋友声明很好奇。我个人从未使用过它,但我对探索这门语言很感兴趣。
使用friend的一个好例子是什么?
读了一些常见问题,我喜欢<< >>操作符重载和添加作为这些类的朋友的想法。然而,我不确定这如何不会破坏封装。什么时候这些异常可以保持在OOP的严格范围内?
当前回答
简短的回答是:在friend确实可以改善封装时使用它。提高可读性和可用性(操作符<<和>>是典型的例子)也是一个很好的理由。
至于改进封装的例子,专门设计用于处理其他类的内部结构的类(想到了测试类)是很好的候选。
其他回答
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.
当不同的类(不是从另一个类继承一个类)正在使用另一个类的私有或受保护成员时,可以使用友情。
友元函数的典型用例是 在访问私有或受保护的两个不同的类之间进行 两者的成员。
来自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;
}
编辑:阅读faq有点长,我喜欢<< >>操作符重载和添加作为这些类的朋友的想法,但我不确定这如何不打破封装
它将如何破坏封装?
当允许对数据成员进行不受限制的访问时,就打破了封装。考虑以下类:
class c1 {
public:
int x;
};
class c2 {
public:
int foo();
private:
int x;
};
class c3 {
friend int foo();
private:
int x;
};
C1显然没有封装。任何人都可以读取和修改其中的x。我们没有办法实施任何形式的访问控制。
C2明显被封装了。没有对x的公共访问。你所能做的就是调用foo函数,它对类执行一些有意义的操作。
c3吗?它的封装程度低吗?它是否允许无限制地访问x?它是否允许未知函数访问?
不。它只允许一个函数访问类的私有成员。就像c2一样。就像c2一样,有访问权的函数不是“某个随机的未知函数”,而是“类定义中列出的函数”。就像c2一样,通过查看类定义,我们可以看到拥有访问权限的完整列表。
那么,这到底是如何减少封装的呢?同样数量的代码可以访问类的私有成员。类定义中列出了所有具有访问权限的人。
Friend不会破坏封装。这让一些Java程序员感到不舒服,因为当他们说“面向对象”时,他们实际上指的是“Java”。当他们说“封装”时,他们并不是说“必须保护私有成员不受任意访问”,而是说“在Java类中,唯一能够访问私有成员的函数是类成员”,尽管出于几个原因,这完全是无稽之谈。
首先,如上所述,它限制太大。没有理由不允许朋友方法做同样的事情。
第二,限制不够。考虑第四个类:
class c4 {
public:
int getx();
void setx(int x);
private:
int x;
};
根据上述Java思想,这是完美封装的。 但是,它允许任何人读取和修改x,这有什么意义呢?(提示:事实并非如此)
底线: 封装是关于能够控制哪些函数可以访问私有成员。这与这些函数的定义具体位于何处无关。
您使用私有/受保护/公共权限控制成员和函数的访问权限? 所以假设这3个层面中的每一个都很清楚,那么很明显我们遗漏了一些东西……
例如,将成员/函数声明为protected是非常通用的。你的意思是,这个功能对每个人来说都是遥不可及的(当然,继承的孩子除外)。但是异常呢?每个安全系统都让你有某种类型的“白名单”,对吗?
所以,“朋友”让你拥有坚如磐石的对象隔离的灵活性,但也允许为你认为合理的事情创造一个“漏洞”。
我想人们之所以说不需要它,是因为总有一种设计可以不需要它。我认为这类似于讨论全局变量:你永远不应该使用它们,总有办法不用它们……但在现实中,你会看到在某些情况下,这是(几乎)最优雅的方式……我认为朋友之间也是如此。
它实际上没有任何好处,除了让你在不使用设置函数的情况下访问成员变量
但这并不是正确的看法。 其理念是控制WHO可以访问什么,是否有设置功能与此关系不大。
您可以坚持最严格和最纯粹的OOP原则,并确保任何类的数据成员都没有访问器,这样所有对象都必须是唯一可以知道它们的数据的对象,并且对它们进行操作的唯一方法是通过间接消息(即方法)。
但即使是c#也有一个内部可见性关键字,Java也有默认的包级可访问性。c++实际上更接近于OOP的理想,它通过精确地指定哪些其他类或只有其他类可以看到一个类,从而最大限度地减少了类的可见性。
我不太使用c++,但如果c#有朋友,我会用它来代替我经常使用的汇编全局内部修饰符。它并没有真正打破封装,因为。net中的部署单元是一个程序集。
但是还有InternalsVisibleToAttribute(otherAssembly),它的作用类似于跨组装的友元机制。微软将此用于可视化设计器程序集。