C++ FAQ Lite[14]--友元(更新)

[14] 友元
(Part of C++ FAQ Lite, Copyright © 1991-2001, Marshall Cline, cline@parashift.com)

简体中文版翻译:申旻nicrosoft@sunistudio.com东日制作室东日文档


FAQs in section [14]:


[14.1] 什么是友元(friend)?

允许另一个类或函数访问你的类的东西。

友元可以是函数或者是其他的类。类授给它的友元特别的访问权。通常同一个开发者会在技术和非技术上控制类的友元和成员函数(否则当你想更新你的类时,还要征得其它部分的拥有者的同意)。

TopBottomPrevious sectionNext section ]


[14.2] 友元破坏了封装吗?UPDATED!

[Recently made a bit more emphatic (on 4/01). Click here to go to the next FAQ in the "chain" of recent changes .]

如果被适当的使用,实际上可以增强封装。

当一个类的两部分会有不同数量的实例或者不同的生命周期时,你经常需要将一个类分割成两部分。在这些情况下,两部分通常需要直接存取彼此的数据(这两部分原来在同一个类中,所以你不必增加直接存取一个数据结构的代码;你只要将代码改为两个类就行了)。实现这种情况的最安全途径就是使这两部分成为彼此的友元。

如果你象刚才所描述的那样使用友元,就可以使私有的(private)保持私有。不理解这些的人在以上这种情形下还天真的想避免使用友元,他们要么使用公有的(public)数据(罕见!),要么通过公有的 get()set()成员函数使两部分可以访问数据。而他们实际上破坏了封装。只有当在类外(从用户的角度)看待私有数据仍“有意义”时,为私有数据设置公有的get()set()成员函数才是合理的。在许多情况下,这些 get()/set()成员函数和公有数据一样差劲:它们仅仅隐藏了私有数据的名称,而没有隐藏私有数据本身。

同样,如果你将友元函数当做一种类的public:存取函数的语法不同的变种来使用的话,友元函数就和破坏封装的成员函数一样会破坏封装。换一种说法,类的友元不会破坏封装的壁垒:和类的成员函数一样,它们就是封装的壁垒。

TopBottomPrevious sectionNext section ]


[14.3] 使用友元函数的优缺点是什么?

友元函数在接口设计选择上提供了一定程度的自由。

成员函数和友元函数具有同等的特权(100% 的)。主要的不同在于友元函数象f(x)这样调用,而成员函数象 x.f()这样调用。因此,可以在成员函数(x.f())和友元函数(f(x))之间选择的能力允许设计者选择他所认为更具可读性的语法来降低维护成本。

友元函数主要缺点是需要额外的代码来支持动态绑定时。要得到虚友元(virtual friend)的效果,友元函数应该调用一个隐藏的(通常是 protected:成员函数。这称为虚友元函数用法(Virtual Friend Function Idiom)。例如:

 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()将获得控制权。注意派生类覆盖的是保护的虚(protected: virtual)成员函数 do_f(); 而不是它友元函数f(Base&)

TopBottomPrevious sectionNext section ]


[14.4] “友元关系既不继承,也不传递”是什么意思?UPDATED!

[Recently added the "not reciprocal" item thanks to Karel Roose (on 4/01). Click here to go to the next FAQ in the "chain" of recent changes .]

仅仅因为我承认对你的友情,允许你访问我,并不自动地允许你的孩子访问我,并不自动地允许你的朋友访问我,并不自动地允许我访问你。

  • 我不必信任我朋友的孩子。友元的特权不被继承。友元的派生类不一定是友元。如果 Fred 类声明Base类是友元,那么Base类的派生类不会自动地被赋予对于Fred的对象的访问特权。
  • 我不必信任我朋友的朋友。友元的特权不被传递。友元的友元不一定是友元。如果Fred类声明Wilma类是友元,并且Wilma类声明Betty类是友元,那么Betty类不会自动地被赋予对于Fred的对象的访问特权。
  • 你不必仅仅因为我声称你是我的朋友就信任我。友元的特权不是自反的。如果Fred类声明Wilma类是友元,则Wilma对象拥有访问Fred对象的特权,但Fred对象不会自动地拥有对Wilma对象的访问特权。

TopBottomPrevious sectionNext section ]


[14.5] 我的类应该使用成员函数还是友元函数?

尽量使用成员函数,不得已时使用友元。

有时在语法上,友元更好(例如,Fred类中,友元函数允许Fred参数作为第二个参数,而成员函数必须是第一个)。另一个好的用法是二元中缀运算符。例如,如果你想允许aFloat + aComplex 的话,aComplex + aComplex 应该被定义为友元而不是成员函数。(成员函数不允许提升左边的参数,因为那样会改变成员函数调用对象的类)。

在其他情况下,首选成员函数。

TopBottomPrevious sectionNext section ]


E-Mail E-mail the author
C++ FAQ LiteTable of contentsSubject indexAbout the author©Download your own copy ]
Revised Apr 8, 2001

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论
<p class="MsoNormal" style="margin-left:-18pt;"> <strong><span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">学习计划</span></span></strong> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">每天学习一小时以上</span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">跟着视频动手编写代码</span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">调试代码并对比课程多提供的源码</span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <strong><span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">课程目标</span></span></strong> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">理解多线程原理并学会</span>c++11 的多线程编程</span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">理解线程池技术原理并能使用</span>c++实现</span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">理解</span>c++11 14 17 20 多线程编程相关特性</span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <strong><span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">常见问题</span></span></strong> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">课程使用的开发工具</span></span><span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">?</span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">课程使用的开发工具是</span>vs2019</span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">课程代码是否是跨平台</span></span><span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">?</span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">课程代码都是基于</span>c++自生特性,没有用到第三方库,都是跨平台</span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">旧版本的开发工具是否可以</span></span><span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">?</span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">课程中的大部分代码是</span>c++11 ,绝大部分开发工具都支持,其中c++14 17要比较新的工具支持,c++20需要vs2019</span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">课程是否提供源码</span></span><span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">?</span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;">课程提供源码,方便同学学习过程的出现问题,进行对照调试错误。</span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;"> <span style="font-family:微软雅黑;font-size:24pt;"><span style="font-family:微软雅黑;"><img alt="" src="https://img-bss.csdnimg.cn/202102171218234096.jpg" /></span></span> </p> <p class="MsoNormal" style="margin-left:-18pt;">   </p> <p class="MsoNormal" style="margin-left:-18pt;">   </p>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

Nicrosoft

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值