你什么时候应该使用朋友课?

App*_*ker 9 c++ oop class-design class friend

可能重复:
你何时应该在C++中使用'friend'?

由于缺乏关于朋友课程的文档,我来到了绊脚石.大多数书籍只是简单地解释一下,例如C++摘录:完整参考:

__PRE__

坦率地说,我从未见过有经验的C++程序员编写的任何优秀代码中的朋友类.所以,这是我的问题列表.

1- Do Inherited Classes与基类有相同的朋友吗?例如,如果我将类foo声明为类库的朋友,那么class der(派生自base)也会将foo作为朋友吗?

2- 应该使用朋友类时的特殊情况是什么?

3-我正在创建一个winapi包装器,我想让WinHandle类成为Widget类的朋友(访问一些受保护的成员).推荐吗?或者我应该使用传统的Get/Set功能访问它们?

And*_*ron 26

Friend用于授予选择性访问权限,就像受保护的访问说明符一样.在使用受保护的确非常有用的正确用例时也很难.

通常,友元类在有意强耦合的设计中很有用:您需要在两个类之间建立特殊关系.更具体地说,一个类需要访问另一个类的内部,并且您不希望使用公共访问说明符授予每个人访问权限.

经验法则:如果public太弱而private太强,则需要某种形式的选择访问:protectedfriend(Java中的包访问说明符提供相同类型的角色).

示例设计

例如,我曾经写过一个简单的秒表类,我希望隐藏原生秒表分辨率,但让用户通过单一方法查询经过的时间,并将单位指定为某种变量(是用户偏好选择,比方说).而不是说elapsedTimeInSeconds(),elapsedTimeInMinutes()等等方法,我想有类似的东西elapsedTime(Unit::seconds).为了实现这两个目标,我不能将原生分辨率公开或私有,所以我提出了以下设计.

实施概述

class StopWatch;

// Enumeration-style class.  Copy constructor and assignment operator lets
// client grab copies of the prototype instances returned by static methods.
class Unit
{
friend class StopWatch;
    double myFactor;
    Unit ( double factor ) : myFactor(factor) {}
    static const Unit native () { return Unit(1.0); }
public:
        // native resolution happens to be 1 millisecond for this implementation.
    static const Unit millisecond () { return native(); }

        // compute everything else mostly independently of the native resolution.
    static const Unit second () { return Unit(1000.0 / millisecond().myFactor); }
    static const Unit minute () { return Unit(60.0 / second().myFactor); }
};

class StopWatch
{
    NativeTimeType myStart;
    // compute delta using `NativeNow()` and cast to
    // double representing multiple of native units.
    double elapsed () const;
public:
    StopWatch () : myStart(NativeNow()) {}
    void reset () { myStart = NativeNow(); }
    double elapsed ( const Unit& unit ) const { return elapsed()*unit.myFactor; }
};
Run Code Online (Sandbox Code Playgroud)

如您所见,此设计实现了两个目标:

  1. 原始分辨率永远不会暴露
  2. 期望的时间单位可以存储等

讨论

我非常喜欢这种设计,因为原始实现存储了多个本机时间单元并执行了一个除法来计算经过的时间.有人抱怨分裂太慢了,我改变了Unit类来缓存红利,让elapsed()方法(一点点)更快.

一般来说,你应该争取强大的凝聚力和弱耦合.这就是为什么朋友很少使用,建议减少类之间的耦合.但是,这里强耦合提供更好的封装情况.在那些情况下,你可能需要一个friend.


Alo*_*ave 6

继承类和基类有相同的朋友吗?例如,如果我将 foo 类声明为 base 类的朋友,那么 der 类(派生自 base)是否也将 foo 作为朋友?

带有friend关键字的规则是:
Friendship属性不被继承。
因此,没有朋友的基类的不会是朋友的派生类。


应该使用友元类的特殊情况有哪些?

坦率地说,(恕我直言)使用朋友类主要是为了实现一些相当易于使用的东西。如果设计软件时考虑了所有要求,那么实际上就不需要友元类。重要的是要注意完美的设计几乎不存在,即使存在也很难实现。

一个需要友元类的示例:
有时可能需要一个测试类(它不是发布软件的一部分)能够访问类的内部来检查和记录某些特定的结果/诊断。在这种情况下使用友元类是有意义的,以方便使用并防止设计开销。


我正在制作一个 winapi 包装器,我想在其中交class WinHandle朋友class Widget(以访问一些受保护的成员)。是否推荐?或者我应该使用传统的 Get/Set 函数访问它们?

我会坚持使用传统的setter/getter。我宁愿避免在可以通过通常的 OOP 构造工作的地方使用朋友。也许,我对使用相当偏执,friend因为如果我的类将来更改/扩展,我会发现朋友的非继承属性会导致我出现问题。


编辑:
来自 的评论@Martin和来自的优秀答案@André Caron提供了关于friend船舶使用的全新视角,这是我以前从未遇到过的,因此没有在上面的答案中说明。我将保留这个答案,因为它帮助我学习了一个新的观点,希望它能帮助学习具有类似观点的人。