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 。
继承类是否与基类有相同的 friend ?例如,如果我将类 foo 声明为类 base 的友元,类 der
(派生自 base)是否也将 foo 作为友元?
应该使用友元类的特殊情况是什么?
我正在制作一个 winapi 包装器,我想在其中使类 WinHandle 成为类 Widget 的友元(以访问一些 protected 成员)。推荐吗?或者我应该只使用传统的 Get/Set 函数访问它们?
Friend 用于授予选择性访问,就像 protected 访问说明符一样。也很难想出使用 protected 真正有用的正确用例。
通常,友元类在存在有意强耦合的设计中很有用:您需要在两个类之间建立特殊关系。更具体地说,一个类需要访问另一个类的内部结构,而您不希望使用公共(public)访问说明符向所有人授予访问权限。
经验法则:如果 public 太弱而 private 太强,您需要某种形式的选定访问权限:protected或 friend(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; }
};
如您所见,此设计实现了两个目标:
- native 分辨率永远不会暴露
- 可以存储所需的时间单位等。
讨论
我非常喜欢这个设计,因为最初的实现存储了本地时间单位的倍数并执行除法以计算耗时。有人提示除法太慢后,我更改了 Unit
类来缓存被除数,使 elapsed()
方法(稍微)更快。
总的来说,应该力求强内聚弱耦合。这也是为什么friend这么少用的原因,建议降低类之间的耦合度。但是,在情况下,强耦合可以提供更好的封装。在这些情况下,您可能需要一个 friend
。