c++ - 什么时候应该使用友元类?

标签 c++ oop class class-design friend

<分区>

Possible Duplicate:
When should you use 'friend' in C++?

由于缺乏友元类的文档,我遇到了一个绊脚石。大多数书籍只是简单地解释它,例如 C++:完整引用 的摘录:

Friend Classes are seldom used. They are supported to allow certain special case situations to be handled.

坦率地说,我从未在有经验的 C++ 程序员编写的任何优秀代码中看到友元类。所以,这是我的问题 list 。

  1. 继承类是否与基类有相同的 friend ?例如,如果我将类 foo 声明为类 base 的友元,类 der(派生自 base)是否也将 foo 作为友元?

  2. 应该使用友元类的特殊情况是什么?

  3. 我正在制作一个 winapi 包装器,我想在其中使类 WinHandle 成为类 Widget 的友元(以访问一些 protected 成员)。推荐吗?或者我应该只使用传统的 Get/Set 函数访问它们?

最佳答案

Friend 用于授予选择性访问,就像 protected 访问说明符一样。也很难想出使用 protected 真正有用的正确用例。

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

经验法则:如果 public 太弱而 private 太强,您需要某种形式的选定访问权限:protectedfriend(Java 中的包访问说明符起着相同的作用)。

示例设计

例如,我曾经写过一个简单的秒表类,我想在其中隐藏 native 秒表分辨率,但让用户使用单个方法查询耗时,并将单位指定为某种变量(例如,由用户偏好选择)。而不是说 elapsedTimeInSeconds()elapsedTimeInMinutes() 等方法,我想要类似 elapsedTime(Unit::seconds)。为了实现两个这两个目标,我无法将 native 分辨率设置为公开或私有(private),因此我提出了以下设计。

实现概述

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; }
};

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

  1. native 分辨率永远不会暴露
  2. 可以存储所需的时间单位等。

讨论

我非常喜欢这个设计,因为最初的实现存储了本地时间单位的倍数并执行除法以计算耗时。有人提示除法太慢后,我更改了 Unit 类来缓存被除数,使 elapsed() 方法(稍微)更快。

总的来说,应该力求强内聚弱耦合。这也是为什么friend这么少用的原因,建议降低类之间的耦合度。但是,在情况下,强耦合可以提供更好的封装。在这些情况下,您可能需要一个 friend

关于c++ - 什么时候应该使用友元类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6718209/

相关文章:

c++ - 在不修改集合的情况下按排序顺序遍历集合的算法?

实例化时的 PHP 类成员访问

Python 类 self.variables

c++ - 返回指定类型的泛型函数

c++ - 使用 lib 和 dll 文件隐藏实现?

c++ - 在类中重载运算符+

java - 静态方法与静态数据

oop - 大类重构规则

c# - 我是否使用了错误的设置/获取功能?

c++ - __asm__ 在 C++ 错误