荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Second (石开), 信区: Program
标  题: Part of C++ FAQ Lite[14]--友元
发信站: 荔园晨风BBS站 (Thu Jun  7 05:51:28 2001), 转信

[14] 友元
(part of c++ faq lite, copyright ? 1991-96, marshall cline, cline@parashift.
com)
----------------------------------------------------------------------------
----
faqs in section [14]:
[14.1] 什么是友元?
[14.2] 友元破坏了封装吗?
[14.3] 使用友元函数的优缺点是什么?
[14.4] “友元关系既不继承,也不传递”是什么意思?
[14.5] 我的类应该使用成员函数还是友元函数?
----------------------------------------------------------------------------
----
[14.1] 什么是友元?
允许另一个类或函数访问你的类的东西。
友元可以是函数或者是其他类。一个类授给它的友元特别的访问权。通常同一个开发者

会在技术和非技术上控制类的友元和成员函数(否则当你想更新你的类时,还要征得其

它部分的拥有者的同意)
----------------------------------------------------------------------------
----
[14.2] 友元破坏了封装吗?
如果被适当的使用,实际上可以增强封装。
当一个类的两部分会有不同数量的实例或者不同的生命周期时,你经常需要将一个类分

成两部分。在这些情况下,两部分通常需要直接存取彼此的数据(这两部分原来在同一

类中,所以你不必增加直接存取一个数据结构的代码;你只要将代码改为两个类就行了
)。
实现这种情况的最安全途径就是使这两部分成为彼此的友元。
如果你象刚才所描述的那样使用友元,就可以使私有的保持私有。不理解这些的人在以

这种情形下还天真的想避免使用友元。他们要么使数据公有(罕见!),要么通过公有

get()和set()成员函数使两部分可以访问数据。而他们实际上破坏了封装。只有当在类

(从用户的角度)看待私有数据仍“有意义”时,为私有数据设置公有的get()和set()

员函数才是合理的。在许多情况下,这些 get()/set()成员函数和公有数据一样差劲:

们仅仅隐藏了私有数据的名称,而没有隐藏私有数据本身。
同样,如果你将友元函数当做一种类的public:存取函数的语法不同的变种来使用的话,

元函数就和破坏封装的成员函数一样会破坏封装。换一种说法,类的友元不会破坏封装
的壁
垒:和类的成员函数一样,它们就是封装的壁垒。
----------------------------------------------------------------------------
----
[14.3] 使用友元函数的优缺点是什么?
友元函数在接口设计选择上提供了一定程度的自由。
成员函数和友元函数具有同等的特权(100% 的)。主要的不同在于友元函数象 f(x)这

调用,而成员函数象 x.f()这样调用。因此,可以在成员函数(x.f())和友元函数(f
(x))
之间选择的能力允许设计者选择他所认为更具可读性的语法来降低维护成本。
友元函数主要缺点是需要额外的代码来支持动态绑定时。要得到虚友元的效果,友元函

应该调用一个隐藏的(同时是 protected:)虚成员函数。这称为虚友元函数。例如:
    class base {
    public:
      friend void f(base& b);
      // ...
    protected:
      virtual void do_f();
      // ...
    };
    inline void f(base& b)
    {
      b.do_f();
    }
    class derived : public base {
    public:
      // ...
    protected:
      virtual void do_f();  // "覆盖" f(base& b)的行为
      // ...
    };
    void usercode(base& b)
    {
      f(b);
    }
在usercode(base&)中的f(b)语句将调用虚拟的 b.do_f()。这意味着如果b实际是一个
派生类的对象,那么derived::do_f()(派生类的do_f())将获得控制权。注意派生类
覆盖的是保护的虚成员函数 do_f(); 而不是它友元函数 f(base&)。
----------------------------------------------------------------------------
----
[14.4] “友元关系既不继承,也不传递”是什么意思?
我可以声称你是我的朋友,但这并不意味着你的孩子或你的朋友就一定是我的朋友。
朋友的孩子不一定是朋友,友元关系不被继承。友元的派生类不一定是友元。如果
fred类声明base类是友元,那么从base派生的类并不会自动拥有访问fred对象的特权。

朋友的朋友不一定是朋友。友元关系不被传递。友元的友元不一定是友元。如果fred类

声明了 wilma类为友元,并且wilma声明了betty类为友元,那么betty类对fred 对象没

有有任何特殊的访问特权。
----------------------------------------------------------------------------
----
[14.5] 我的类应该使用成员函数还是友元函数?
尽量使用成员函数,不得已时使用友元。
有时在语法上,友元更好(例如,fred类中,友元函数允许fred参数作为第二个参数,

而成员函数必须是第一个)。另一个好的用法是二元中缀运算符。例如,如果你想允
许afloat + acomplex的话,acomplex + acomplex应该被定义为友元而不是成员函数。

(成员函数不允许提升左边的参数,因为那样会改变成员函数调用对象的类)。
在其他情况下,首选成员函数。

--
                            既然热爱生命
                            那么,
                            一切都在意料之中。

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.28.16]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店