c++ 友元 friend的好处是?

zhuyf87 2013-02-19 06:45:52
友元函数,或者友元类,可以访问一个类的private成员。

class B 
{
friend class A;

public:
explicit B(int i) {
data = i;
}

private:
int data;
};

class A
{
public:
void func(B &b) {
b.data = 10;
}
};



这是 友元的 一般功能。但是这个也可以通过其他方式实现啊。
比如在func里面通过B类的public接口修改data:

class B 
{
public:
explicit B(int i) {
data = i;
}

void setData(int i) {
data = i;
}

private:
int data;
};

class C
{
public:
void func(B &b) {
b.setData(10);
}
};


我没看到 友元 机制有什么特别的用处呢?比如什么事情是非友元实现不了的?
请大家帮忙指点。谢谢。
...全文
1678 42 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
_寒江雪_ 2015-08-20
  • 打赏
  • 举报
回复
楼主是这样的,看了你的问题,我突然想到我看的Primer plus里面讲友元的时候举的例子是电视机和遥控器两个类 楼上的各位都回答得很精彩,受益良多 不过我补充一下 为什么要使用友元 电视机换台的时候,只能一个频道一个频道连续地切换,而不能跳频道切换。 于是电视机类就只有一个换台的公有接口,且只能一个频道一个频道地切换 遥控器不是电视机,没有电视机的属性 不成继承关系 声明为电视机的友元,可以访问到电视机的数据,遥控器和电视机匹配,通过使用遥控器(的方法)可以实现跳频道切换。遥控器独有的电视机没有的功能,而且只有遥控器有,而其他类比如电冰箱没有。
billzheng 2013-02-24
  • 打赏
  • 举报
回复
友元只对特定目标开放,而public对所有目标开放,两者作用不同,不可相互替代。你举的这个例子是不对的。只允许部分类或函数访问自己的私有成员,其它人不行,这件事非友元不能做。 友元并没有破坏封装。将何人设成友元,或者说允许谁来访问本类的私有成员,完全是由本类的作者决定的,如同将哪些成员设成公共成员一样。public控制开放哪些成员,friend控制开放的目标,是控制的两种表现形式,并不是对立的,所以从概念上讲并没有破坏封装。 我第一次听说友元没有破坏封装。不管是面向过程还是面向对象编程,都讲的是数据隐藏;封装是为了数据隐藏,既然友元函数/对象都能毫无限制的访问所有成员,封装已不受控制,还没有破坏封装? 所谓“封装”,并不是说把所有的东西都包起来不给别人看,而是指有控制的允许一些人看到一些东西,强调的是“控制”,而不是“隐藏”。有“隐藏”必有“开放”,否则就谈不上封装了,关键在于作者能不能控制这种开放。有的语言不能控制,就说它不具有“封装”特性,有的语言能够控制,就说它具有“封装”特性。 只要你定义了public接口,你无法控制你的类被谁使用。你怎么控制你的对象之被某些人调用? 你只能控制你的某个接口是public,所以所有的编程还是讲的隐藏。一个类的作者只能控制这种开放而不是谁能调用你的类。如果你实在要争执,去买 <<code complete II>>来读读。 C++的“封装”特性是指其能够“控制开放”,友元只是细化这种控制,并没有失去控制,所以并没有破坏“封装”。类似还有protected,只允许特定目标访问特定成员,也是对“封装”的细化,都在类的作者的控制之下。 基本的封装概念没有理解,在作者的控制之下就能够说一个类的封装没有被破坏? 类的封装是指作者的控制权? 最初曾考虑过将friend进一步细化到控制单独的成员,也就是说同时控制开放成员与目标,不过语法上太别扭了,所以现在friend作用于所有成员,public作用于所有目标。 就这种编程能力,你还是全部public得了。
billzheng 2013-02-24
  • 打赏
  • 举报
回复
引用 26 楼 zhuyf87 的回复:
友元 在 重载操作符时比较有用,但也不是必须用友元来实现。 谢谢8楼,你的答案是我想要的。谢谢大家。 准备结贴给分了。
8楼的知识点基本上都所错误的。
zhuyf87 2013-02-24
  • 打赏
  • 举报
回复
友元 在 重载操作符时比较有用,但也不是必须用友元来实现。 谢谢8楼,你的答案是我想要的。谢谢大家。 准备结贴给分了。
zhuyf87 2013-02-24
  • 打赏
  • 举报
回复
引用 40 楼 zhangtonghui816 的回复:
引用 38 楼 zhuyf87 的回复:引用 35 楼 zhangtonghui816 的回复:引用 1 楼 zhuyf87 的回复:而且我感觉 友元 机制,也破坏了本来的封装特性。 某些运算符重载不用friend根本没法实现吧,比如<< 引用 15 楼 chuachua66 的回复:加法就必须用友元吧,以前的哪本书讲过,primer还是effective c……
嗯。是的,重载一般不应破坏操作符原来的特性和使用习惯,最好定义为友元。 这个问题讨论的差不多了。结贴。谢谢大家。^_^
zhangtonghui816 2013-02-24
  • 打赏
  • 举报
回复
引用 38 楼 zhuyf87 的回复:
引用 35 楼 zhangtonghui816 的回复:引用 1 楼 zhuyf87 的回复:而且我感觉 友元 机制,也破坏了本来的封装特性。 某些运算符重载不用friend根本没法实现吧,比如<< 引用 15 楼 chuachua66 的回复:加法就必须用友元吧,以前的哪本书讲过,primer还是effective c++? << 和 +,都可以定义为……
成员函数要求是有对象调用,则第一个参数必须是类的对象,但是<<和>>第一个参数是流的对象引用。 故,不能使用成员函数。 如果你认为<<cout和>>cin也可以的话,那我觉得ok的。
mujiok2003 2013-02-24
  • 打赏
  • 举报
回复
友元机制是为了对部分用户开后门,如果换成public后就变成完全开放,完全没有限制。 典型场景:运算重载。
zhuyf87 2013-02-24
  • 打赏
  • 举报
回复
引用 35 楼 zhangtonghui816 的回复:
引用 1 楼 zhuyf87 的回复:而且我感觉 友元 机制,也破坏了本来的封装特性。 某些运算符重载不用friend根本没法实现吧,比如<<
引用 15 楼 chuachua66 的回复:
加法就必须用友元吧,以前的哪本书讲过,primer还是effective c++?
<< 和 +,都可以定义为类的成员函数,所以不用友元也能实现。只不过是比如+这种算术运算符,最好定义为普通非成员函数,这时就需要友元了。
zhangtonghui816 2013-02-24
  • 打赏
  • 举报
回复
引用 15 楼 chuachua66 的回复:
加法就必须用友元吧,以前的哪本书讲过,primer还是effective c++?
不一定必须是友元,但是友元好些 因为1+a 私有会报错 只能是a+1 或者b+a,a+b 而友元不会
zhangtonghui816 2013-02-24
  • 打赏
  • 举报
回复
还有就是 在运算时,有数和对象的混合运算时,运算符重载最好使用友元
zhangtonghui816 2013-02-24
  • 打赏
  • 举报
回复
引用 1 楼 zhuyf87 的回复:
而且我感觉 友元 机制,也破坏了本来的封装特性。
某些运算符重载不用friend根本没法实现吧,比如<<
dingqiang107 2013-02-24
  • 打赏
  • 举报
回复
引用 33 楼 billzheng 的回复:
即使单独把BS的语言翻出来作为引用,那么你的表达还是有错误的. 毫无上下文的表达是很苍白和容易被误解的。比如下面一个问题: class A 和 class B是两个独立的类,Class B希望能够获取Class A 的其中一个成员,把class B申明为class A的友元,是不是破坏封装?
“封装”是指C++语言(或是广泛地说面向对象语言)的封装机制,不是从字面意义上理解的“封起来“。封装机制的要点是控制开放,或者说授予访问权,详细地说,就是决定哪些人能看到哪些内容。“隐藏”与“开放”是对立统一的,在决定“隐藏”什么同时,就决定了要“开放”什么。把“封装机制”说成是“开放机制”也无不可,意思一样,就看当初命名时用哪个词顺口。 控制开放的方式,既可先划定一个大范围的开放,再决定其中哪些隐藏,也可以先划定一个大范围的隐藏,再决定其中哪些开放。前者的例子是struct,后者的例子是class。这是因为要兼容C的用法,并不是必须要这样做。这是控制开放成员的情况。 控制开放目标的情况只设计了缺省隐藏后用friend显示开放,从表面上看,像是在“开放”,不像是在“隐藏”。假如说换一个关键字secret,控制哪些类或函数不可访问本类的公有成员,这看上去就更像是在“隐藏”了,其实在控制机制上与friend没什么区别,只是语法细节不同。 总之,封装的目的就是要控制哪些人可以访问哪些内容,通过private,public和friend的组合来实现。friend是封装机制的一部分,怎么能说是破坏封装呢?能说private是破坏开放机制吗? 我不觉得“合理的使用friend”与“使用friend“的结论有什么文字游戏以外意义上的不同,这里的一切讨论当然是指合理的使用。由于”不合理的使用“造成的”破坏XX“的情况,对于一切语言机制都适用,这是使用者的问题,不是语言的问题。“不合理的使用指针”会造成系统崩溃,能说C++的指针机制造成系统崩溃吗? 你举的例子,如果class A不想让class B以外的类访问,那只能加B为友元。“封装”就是用来控制访问权的,class B想访问class A的成员,怎么能说A/B根本没什么关系呢? 你的第二个例子,只是两个类相互访问,又不想被第三者插足,不过是friend的一个特殊应用而已。
billzheng 2013-02-24
  • 打赏
  • 举报
回复
引用 31 楼 dingqiang107 的回复:
引用 28 楼 billzheng 的回复:我第一次听说友元没有破坏封装。不管是面向过程还是面向对象编程,都讲的是数据隐藏;封装是为了数据隐藏,既然友元函数/对象都能毫无限制的访问所有成员,封装已不受控制,还没有破坏封装? Bjarne Stroustrup 《C++语言的设计与演化》(中文版)第46页: 访问权的授予方式就是把一个成员的声明放在类声明的公用部……
即使单独把BS的语言翻出来作为引用,那么你的表达还是有错误的. 毫无上下文的表达是很苍白和容易被误解的。比如下面一个问题: class A 和 class B是两个独立的类,Class B希望能够获取Class A 的其中一个成员,把class B申明为class A的友元,是不是破坏封装? 正确的说法是“合理的使用friend”不仅没有破坏封装,而且还帮助封装. 上面的例子使用了友元就是破坏了封装了,因为A/B根本没有什么关系,将友元授予了B就是破坏了封装。 那么什么情况下友元又是帮助封装呢? 比如有A和B本来属于一个类,或者A/B具有非常高的耦合,A没有B无法提供功能,B没有A功能不全,那么这个时候使用友元就是提升了封装。因为有了友元A/B类各自有了更好的封装,各自的职责更清晰,但是又互相支持。如果不把A/B分开成两个类,那么原来的类变得臃肿。
dingqiang107 2013-02-24
  • 打赏
  • 举报
回复
从BS的说法可以看出,C++的封装机制从一开始就是由private、public和friend共同组成的,其中public和friend分别用于不同方式的控制开放,friend并不是为了破坏封装而打的补丁。 protected倒是后来版本才加进来的。注意protected同时控制开放内容和开放目标,兼有public和friend的特征。如果承认protected是封装机制的一部分,那么就要承认对开放目标的控制是封装机制的一部分,自然专门控制开放目标的friend也是封装机制的一部分。 据BS说,因为他以前从事过操作系统的开发,所以从操作系统(而不是从其它编程语言)那里借鉴证了“保护概念”。具体地说就是访问权的授予,这个思想后来才被总结为面向对象的封装机制。“授予访问权”也就是我前面说的“控制开放”,这才是封装机制的核心。所以,封装机制强调的是“控制”,而不是“隐藏”
dingqiang107 2013-02-24
  • 打赏
  • 举报
回复
引用 28 楼 billzheng 的回复:
我第一次听说友元没有破坏封装。不管是面向过程还是面向对象编程,都讲的是数据隐藏;封装是为了数据隐藏,既然友元函数/对象都能毫无限制的访问所有成员,封装已不受控制,还没有破坏封装?
Bjarne Stroustrup 《C++语言的设计与演化》(中文版)第46页: 访问权的授予方式就是把一个成员的声明放在类声明的公用部分,或是把某个特定函数或者类声明为一个friend。 友元关系被看成一种机制,类似于一个保护域将读写的权力授与另一个,这需要在类声明中明显写出,而且是特指的。因此我从来都不能认同反复出现的friend声明“侵犯了封装机制”的断言,它们不过是用非C++术语表达的无知和混乱。 第48页: 多年来也出现了许多建议,希望能提供对小于整个类的单元的保护,例如: grant X::f(int) access to Y::a, Y::b, and Y::g(char); 我一直在抗拒这类建议。我的基本想法是这种小粒度控制不会增加任何保护……由更多显式控制得到的利益抵不上它所带来的在描述、实现和使用方面的复杂性。
lzjamao 2013-02-24
  • 打赏
  • 举报
回复
引用 28 楼 billzheng 的回复:
友元只对特定目标开放,而public对所有目标开放,两者作用不同,不可相互替代。你举的这个例子是不对的。只允许部分类或函数访问自己的私有成员,其它人不行,这件事非友元不能做。 友元并没有破坏封装。将何人设成友元,或者说允许谁来访问本类的私有成员,完全是由本类的作者决定的,如同将哪些成员设成公共成员一样。public控制开放哪些成员,friend控制开放的目标,是控制……
说得太好了!
lzjamao 2013-02-24
  • 打赏
  • 举报
回复
举个例子,有一个工厂类叫CFactory,它有一个接口 IObject CreateObject(); CObject, CObject2等继承自IObject。 CreateObject() 为了向调用者隐藏具体的IObject实现类,并且要求调用者不能私自创建IObject的具体类对象。 一句话,我们想只对CFactory开放,IObject具体类对象的创建。所以我们把各IObject具体类的构造函数声明为私有,向CFactory声明为friend。
zhangwuji156 2013-02-21
  • 打赏
  • 举报
回复
没看别人的回复,就说我用到的地方吧. 不知道你有没有看过设计模式这样的书,比如要写一些算法,这些算法的基本骨架一样,可以把这些算法里可以合并(复用)的单元,写成一些类,而这些类单独在外面用,是没法用的,但避免不了用户看到这个类后,自己用.那就把这些个单元类全部的函数都私有化.而把那个算法骨架设为这些类的友元类,这样就只有这个算法骨架类可以利用这些算法单元.
xwfde 2013-02-21
  • 打赏
  • 举报
回复
8#说的很清楚了,只让部分函数或类访问本类的私有数据,非友员不能做。
躺着睡的蜗牛 2013-02-20
  • 打赏
  • 举报
回复
在线程里通过友元访问类的私有成员感觉挺好用的, 要不就得定义全局变量了。
加载更多回复(22)

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧