我正在刷新我的C ++(我是一名Java开发人员),我偶然发现了friend class
关键字,我已经忘记了一段时间。这是其中一个功能只是厨房水槽的一部分,还是有充分理由这样做而不仅仅是一个香草吸气剂?我理解它的区别在于它限制了谁可以访问数据,但我不能想到有必要的场景。
注意:我已经看到了类似的问题,但具体我问,这只是一个高级功能,除了让人们看到你的代码时会感到困惑,直到他们意识到你在做什么之后才会增加真正的价值?
答案 0 :(得分:40)
我同意评论说如果明智地使用了friend关键字可以改进封装。我只想补充说,朋友类最常见(合法!)的使用可能正在测试。您可能希望测试人员类具有比其他客户端类更大的访问权限。测试者类可以有充分的理由查看故意隐藏在其他类中的内部细节。
答案 1 :(得分:19)
根据我的经验,与用于打破封装的频率相比,实际增强数据封装的朋友(或可变的,有点相似)的情况很少见。
这对我来说很少有用,但是当我使用它时,我不得不将以前属于单个类的类分成两个需要访问某些常用数据/功能的独立类。
编辑以回应Outlaw Programmer的评论:我们绝对同意这一点。分开它们之后除了朋友的类之外的另一个选择是制作公共访问者,这有时会破坏封装!我认为有些人认为友好类会以某种方式破坏封装,因为他们已经看到它使用不当,很多人可能永远不会看到正确使用的代码,因为这是一件罕见的事情。我喜欢你的陈述方式 - 友善是一个很好的中间地带,不允许你分开你的课程,让所有人都能接触到公众。
编辑以响应David Thornley:我同意C ++允许您执行此类操作的灵活性是C ++中设计决策的结果。我认为这就是通过灵活的语言理解什么是好的和坏的风格更重要的事情。 Java的观点是你永远不应该有朋友类,以便不提供这些类,但作为C ++程序员,我们作为一个社区的责任是定义这些非常灵活但有时被滥用的语言结构的恰当使用。
编辑以响应Tom:Mutable并不一定会打破封装,但是我在实际情况中看到的mutable关键字的许多用法都破坏了封装,因为看到人们打破封装更常见可变性比实际上找到并理解正确使用mutable一样。
答案 2 :(得分:13)
当您希望一个类(Factory)负责创建另一个类(Type)的实例时。您可以使Type的构造函数为private,从而确保只有Factory可以创建Type对象。当您希望将检查委托给可以作为验证器的其他类时,它非常有用。 只是一种使用场景。
P.S。真的错过了C#中的“朋友”关键字...
答案 3 :(得分:8)
具体实例是类工厂,您希望只通过另一个工厂类创建一个类,因此您将构造函数设为私有,而工厂类则是生成类的朋友。
它有点'就像一个2“12点3/4”驱动插座 - 不是非常常见,但是当你需要它时,你会非常高兴你拥有它。
答案 4 :(得分:4)
答案 5 :(得分:2)
答案 6 :(得分:1)
我将friend
构造看作是在极少数情况下应该使用的语言特征之一,但这并不会使它变得无用。有几种模式要求创建friend
类,其中许多已经在此站点的右侧“相关”栏中。 ====>
答案 7 :(得分:1)
当您有多个类和/或函数协同工作以提供相同的抽象或接口时,将使用友谊。经典的例子是实现某种数值类,并且所有非成员运算符函数(*, - ,+,<<<等等)都被给予友谊,以便它们可以处理数值类的私有数据。
这种用例有点罕见,但确实存在,朋友非常有用。
答案 8 :(得分:1)
以下是一个例子,其中有几个,我敢肯定,在不忽视封装原因的情况下,可以合法使用朋友类。
MyClass继承自GeneralClass。 MyClass已经变大了,所以你创建了HelperClass来封装MyClass的一些功能。但是,HelperClass需要访问GeneralClass中的一些受保护函数才能正确执行它的功能,因此你可以让HelperClass成为MyClass的朋友。
这比公开受保护的函数更好,因为它们不需要每个人都可用,但它有助于保持代码以OOP方式组织,以防止MyClass过于复杂。这是有道理的,因为虽然HelperClass没有通过继承与MyClass具体相关,但它确实与它有某种逻辑连接,体现在代码中,并且在设计中,作为“朋友”。
答案 9 :(得分:0)
我总是(并且只)使用朋友进行单元测试私有方法。我可以想象的另一种方法是使用大量的测试方法加载公共接口,这太乱了,所以我更喜欢在单独的测试类中隐藏测试方法。
这样的事情:
class cMyClassTest;
class cMyClass
{
public:
.....
private:
friend cMyClassTest;
int calc(); // tricky algorithm, test carefully
};
class cMyClassTest
{
public:
int test_calc()
{
cMyClass test;
....
int result = test.calc();
if( result == 42 )
return 1;
return 0;
}
};
答案 10 :(得分:0)