我一直在阅读c++常见问题,对朋友声明很好奇。我个人从未使用过它,但我对探索这门语言很感兴趣。
使用friend的一个好例子是什么?
读了一些常见问题,我喜欢<< >>操作符重载和添加作为这些类的朋友的想法。然而,我不确定这如何不会破坏封装。什么时候这些异常可以保持在OOP的严格范围内?
我一直在阅读c++常见问题,对朋友声明很好奇。我个人从未使用过它,但我对探索这门语言很感兴趣。
使用friend的一个好例子是什么?
读了一些常见问题,我喜欢<< >>操作符重载和添加作为这些类的朋友的想法。然而,我不确定这如何不会破坏封装。什么时候这些异常可以保持在OOP的严格范围内?
当前回答
在我之前工作过的一家公司里,我们遇到了一个有趣的问题,我们用朋友来产生良好的影响。我在我们的框架部门工作,我们在自定义操作系统上创建了一个基本的引擎级系统。在内部我们有一个类结构:
Game
/ \
TwoPlayer SinglePlayer
所有这些类都是框架的一部分,由我们的团队维护。该公司所制作的游戏便是基于这一源自games子游戏的框架。问题是Game有各种单人和双人玩家需要访问的东西的接口,但我们不想在框架类之外公开。解决方案是将这些接口设为私有,并允许双人和单人玩家通过友谊访问它们。
事实上,这整个问题本可以通过更好地实施我们的系统来解决,但我们被锁定在我们所拥有的东西上。
其他回答
在工作中,我们广泛地请朋友来测试代码。这意味着我们可以为主应用程序代码提供适当的封装和信息隐藏。但我们也可以有单独的测试代码,使用朋友来检查内部状态和数据进行测试。
可以说,我不会将friend关键字作为设计的重要组成部分。
您可以坚持最严格和最纯粹的OOP原则,并确保任何类的数据成员都没有访问器,这样所有对象都必须是唯一可以知道它们的数据的对象,并且对它们进行操作的唯一方法是通过间接消息(即方法)。
但即使是c#也有一个内部可见性关键字,Java也有默认的包级可访问性。c++实际上更接近于OOP的理想,它通过精确地指定哪些其他类或只有其他类可以看到一个类,从而最大限度地减少了类的可见性。
我不太使用c++,但如果c#有朋友,我会用它来代替我经常使用的汇编全局内部修饰符。它并没有真正打破封装,因为。net中的部署单元是一个程序集。
但是还有InternalsVisibleToAttribute(otherAssembly),它的作用类似于跨组装的友元机制。微软将此用于可视化设计器程序集。
c++的创建者说这并没有破坏任何封装原则,我将引用他的话:
“朋友”是否违反封装? 不。但事实并非如此。“好友”是一种授予访问权限的显式机制,就像会员资格一样。你不能(在符合标准的程序中)在不修改类源的情况下授予自己对类的访问权。
很明显…
安德鲁例子的另一个常见版本,可怕的密码对联
parent.addChild(child);
child.setParent(parent);
与其担心这两行是否总是一起执行,并且顺序一致,你可以将方法设为私有,并有一个friend函数来强制一致性:
class Parent;
class Object {
private:
void setParent(Parent&);
friend void addChild(Parent& parent, Object& child);
};
class Parent : public Object {
private:
void addChild(Object& child);
friend void addChild(Parent& parent, Object& child);
};
void addChild(Parent& parent, Object& child) {
if( &parent == &child ){
wetPants();
}
parent.addChild(child);
child.setParent(parent);
}
换句话说,您可以保持公共接口更小,并强制在友元函数中跨越类和对象的不变量。
在构建容器并希望为该类实现迭代器时,Friend可以派上用场。