基础问题,百分奉上!!

wwmwenzhu 2008-11-20 04:41:47
讨论一下friend 函数和friend 类,使用时注意哪些问题?
问题简单,分却不少,抢分要努力!!
...全文
296 42 打赏 收藏 转发到动态 举报
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
zengjunzheng 2008-11-21
  • 打赏
  • 举报
回复
二楼简洁明了
就呆在云上 2008-11-21
  • 打赏
  • 举报
回复
我也贴一个哈:
  友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。

  友元函数

  友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样。下面举一例子说明友元函数的应用。

  #include
  #include

  class Point
  {
    void Getxy();
    friend double Distance(Point &a, Point &b);
  private:
    double x, y;
  };

  void Point::Getxy()
  {
  cout<<"("<
  }

  double Distance(Point &a, Point &b)
  

  void main()
  {
    Point p1(3.0, 4.0), p2(6.0, 8.0);
    p1.Getxy();
    p2.Getxy();
    double d = Distance(p1, p2);
    cout<<"Distance is"<
  }

  说明:在该程序中的Point类中说明了一个友元函数Distance(),它在说明时前边加friend关键字,标识它不是成员函数,而是友元函数。它的定义方法与普通函数定义一样,而不同于成员函数的定义,因为它不需要指出所属的类。但是,它可以引用类中的私有成员,函数体中a.x,b.x,a.y,b.y都是类的私有成员,它们是通过对象引用的。在调用友元函数时,也是同普通函数的调用一样,不要像成员函数那样调用。本例中,p1.Getxy()和p2.Getxy()这是成员函数的调用,要用对象来表示。而Distance(p1, p2)是友元函数的调用,它直接调用,不需要对象表示,它的参数是对象。(该程序的功能是已知两点坐标,求出两点的距离。)

  友元类

  友元除了前面讲过的函数以外,友元还可以是类,即一个类可以作另一个类的友元。当一个类作为另一个类的友元时,这就意味着这个类的所有成员函数都是另一个类的友元函数。


友元函数要注意一下几点:
友元函数要在一个类体内说明,形式为: 
friend 类型名 友元函数名(形参表);
然后在类体外对友元函数进行定义,定义的格式和普通函数相同,但可以通过对象作为参数直接访问对象的私有成员
友元函数说明如下:
1)必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型,友元函数的说明可以出现在类的任何地方,包括在private和public部分;
2)注意友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用"::"指示属于哪个类,只有成员函数才使用"::"作用域符号;
3)友元函数不能直接访问类的成员,只能访问对象成员,
4)友元函数可以访问对象的私有成员,但普通函数不行;
5)调用友元函数时,在实际参数中需要指出要访问的对象,
cnmghi 2008-11-21
  • 打赏
  • 举报
回复
1)必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型,友元函数的说明可以出现在类的任何地方,包括在private和public部分;
  2)注意友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用"::"指示属于哪个类,只有成员函数才使用"::"作用域符号;
  3)友元函数不能直接访问类的成员,只能访问对象成员;
  4)友元函数可以访问对象的私有成员,但普通函数不行;
  5)调用友元函数时,在实际参数中需要指出要访问的对象,
  6)类与类之间的友元关系不能继承。
whmouse 2008-11-21
  • 打赏
  • 举报
回复
顶一个
在一些不能直接产生派生类或整个是private的类中,通过使用友元函数或友元类,完成对它们的访问。这应该是友元函数或友元类的一种用法吧。
mujiok2003 2008-11-21
  • 打赏
  • 举报
回复
友元函数,请参考25楼,讲到比较到位.

友元类,当A类需要B类的私有成员(数据成员,成员函数)时,可以把A声明为B的友元类
taodm 2008-11-21
  • 打赏
  • 举报
回复
不使用即可。
我在实际编程中就不记得使用过它。
真的要friend的地方还不如直接public。这个friend语法糖没有啥营养,反而容易蛀牙。
wensheng_zh2007 2008-11-20
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 hqin6 的回复:]
破坏oo思想,破坏分装性~~鉴定完毕@!
[/Quote]
顶了
tunnel115 2008-11-20
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 wjh200821 的回复:]
什么是友元(friend)?
允许另一个类或函数访问你的类的东西。
友元可以是函数或者是其他的类。类授予它的友元特别的访问权。通常同一个开发者会出于技术和非技术的原因,控制类的友元和成员函数(否则当你想更新你的类时,还要征得其它部分的拥有者的同意)。
分清成员函数,非成员函数和友元函数
成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行。所以,如果有个函数必须进行动态绑定(见条款38…
[/Quote]

up
解释很全面
asak_1 2008-11-20
  • 打赏
  • 举报
回复
友元函数

通常,类的私有成员只能由本类的成员访问,外部函数只能访问类的成员函数,再由成员函数访问类的私有成员。但是,如果在某个类定义中用friend声明了一个外部函数(也许是其他类的一个成员)后,这个外部函数便可以例外地访问该类的任何私有成员。用friend声明了的外部函数称为这个类的友元函数。

当友元函数是另一个类的成员函数时,应当注意以下几点:

A:友元函数作为一个类的成员函数时,除应当在它所在的类定义中声明之外,还应当在另一个类中声明它的友元关系,声明语句的格式为:

friend 函数类型 函数所在类名::函数名(参数列表);

B:友元函数在引用本类对象的私有成员时无需本类对象的引用参数,但在引用生命它是友元的类的对象中的私有成员时必须有友元类对象的引用参数。

C:一个类的成员函数作另一个类的友元函数时,必须先定义,而不是仅仅声明它。

使用友元函数直接访问对象的私有成员,可以免去再调用类的成员函数所需的开销。同时,友元函数作为类的一个接口,对已经设计好的类,只要增加一条声明语句,便可以使用外部函数来补充它的功能,或架起不同类对象之间联系的桥梁。然而,它同时也破坏了对象封装与信息隐藏,使用时需要谨慎小心。

友元类
[

也可以把一个类而不仅仅是一个函数声明为另一个类的友元类。这时,只需先声明它而不一定需要先定义。

应当注意,友元关系是单向的,并且只在两个类之间有效。即使类X是类Y的友元,类Y是否是类X的友元也要看类X中是否有相应的声明。即友元关系不具有交换性。若类X是类Y的友元,类Y是类Z的友元,也不一定就说明类X是类Z的友元,即友元关系也不具有传递性。

当一个类要和另一个类协同工作时,使一个类成为另一个类的友元类是很有用的。这时友元类中的每一个成员函数都成为了对方的友元函数。
szzwl 2008-11-20
  • 打赏
  • 举报
回复
学习了一个新东东
霍大脚 2008-11-20
  • 打赏
  • 举报
回复
学习了
deerwin1986 2008-11-20
  • 打赏
  • 举报
回复
呵呵 重赏之下 必有勇夫啊 不错不错 大家该说的都说了
顶一个 大家加油 LZ加油!
chenwenxiang 2008-11-20
  • 打赏
  • 举报
回复
学习~!
zhouqing19871024 2008-11-20
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 qqwx_1986 的回复:]
友元函数的特点是能够访问类中的私有成员的非成员函数。
当一个类作为另一个类的友元时,这就意味着这个类的所有成员函数都是另一个类的友元函数。

友元,即有好处,又有不好的地方,就看你怎么用了,如果被适当的使用,实际上可以增强封装。友元能够使得普通函数直接访问类的保护数据,避免了类成员函数的频繁调用,可以节约处理器开销,提高程序的效率,但矛盾的是,即使是最大限度的保护,同样也破坏了类的封装特性,这…
[/Quote]

正解 但得慎用 破坏封装性
lbjfeng 2008-11-20
  • 打赏
  • 举报
回复
只能up一下了。楼上说的那么多

只是关于friend中,就操作符重载特殊点,但是楼上……
哎,不说了不说了
Lnnu_lc 2008-11-20
  • 打赏
  • 举报
回复
貌似讲的差不多了 up一个

顶一个,我也是这么觉得的,只有特别需要的时候才考虑一下,属于特殊的用法,
帅得不敢出门 2008-11-20
  • 打赏
  • 举报
回复
貌似讲的差不多了 up一个
jeff_nie 2008-11-20
  • 打赏
  • 举报
回复
UP楼上.
wjh200821 2008-11-20
  • 打赏
  • 举报
回复
 什么是友元(friend)?
  允许另一个类或函数访问你的类的东西。
  友元可以是函数或者是其他的类。类授予它的友元特别的访问权。通常同一个开发者会出于技术和非技术的原因,控制类的友元和成员函数(否则当你想更新你的类时,还要征得其它部分的拥有者的同意)。
  分清成员函数,非成员函数和友元函数
  成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行。所以,如果有个函数必须进行动态绑定(见条款38),就要采用虚拟函数,而虚拟函数必定是某个类的成员函数。关于这一点就这么简单。如果函数不必是虚拟的,情况就稍微复杂一点。
  看下面表示有理数的一个类:
  class rational {
  public:
  rational(int numerator = 0, int denominator = 1);
  int numerator() const;
  int denominator() const;
  private:
  ...
  };
  这是一个没有一点用处的类。(用条款18的术语来说,接口的确最小,但远不够完整。)所以,要对它增加加,减,乘等算术操作支持,但是,该用成员函数还是非成员函数,或者,非成员的友元函数来实现呢?
  当拿不定主意的时候,用面向对象的方法来考虑!有理数的乘法是和rational类相联系的,所以,写一个成员函数把这个操作包到类中。
  class rational {
  public:
  ...
  const rational operator*(const rational& rhs) const;
  };
  (如果你不明白为什么这个函数以这种方式声明——返回一个const值而取一个const的引用作为它的参数——参考条款21-23。)
  现在可以很容易地对有理数进行乘法操作:
  rational oneeighth(1, 8);
  rational onehalf(1, 2);
  rational result = onehalf * oneeighth; // 运行良好
  result = result * oneeighth; // 运行良好
  但不要满足,还要支持混合类型操作,比如,rational要能和int相乘。但当写下下面的代码时,只有一半工作:
  result = onehalf * 2; // 运行良好
  result = 2 * onehalf; // 出错!
  这是一个不好的苗头。记得吗?乘法要满足交换律。
  如果用下面的等价函数形式重写上面的两个例子,问题的原因就很明显了:
  result = onehalf.operator*(2); // 运行良好
  result = 2.operator*(onehalf); // 出错!
  对象onehalf是一个包含operator*函数的类的实例,所以编译器调用了那个函数。而整数2没有相应的类,所以没有operator*成员函数。编译器还会去搜索一个可以象下面这样调用的非成员的operator*函数(即,在某个可见的名字空间里的operator*函数或全局的operator*函数):
  result = operator*(2, onehalf); // 错误!
  但没有这样一个参数为int和rational的非成员operator*函数,所以搜索失败。
  再看看那个成功的调用。它的第二参数是整数2,然而rational::operator*期望的参数却是rational对象。怎么回事?为什么2在一个地方可以工作而另一个地方不行?
  秘密在于隐式类型转换。编译器知道传的值是int而函数需要的是rational,但它也同时知道调用rational的构造函数将int转换成一个合适的rational,所以才有上面成功的调用(见条款m19)。换句话说,编译器处理这个调用时的情形类似下面这样:
  const rational temp(2); // 从2产生一个临时
  // rational对象
  result = onehalf * temp; // 同onehalf.operator*(temp);
  当然,只有所涉及的构造函数没有声明为explicit的情况下才会这样,因为explicit构造函数不能用于隐式转换,这正是explicit的含义。如果rational象下面这样定义:
  class rational {
  public:
  explicit rational(int numerator = 0, // 此构造函数为
  int denominator = 1); // explicit
  ...
  const rational operator*(const rational& rhs) const;
  ...
  };
  那么,下面的语句都不能通过编译:
  result = onehalf * 2; // 错误!
  result = 2 * onehalf; // 错误!
  这不会为混合运算提供支持,但至少两条语句的行为一致了。
  然而,我们刚才研究的这个类是要设计成可以允许固定类型到rational的隐式转换的——这就是为什么rational的构造函数没有声明为explicit的原因。这样,编译器将执行必要的隐式转换使上面result的第一个赋值语句通过编译。实际上,如果需要的话,编译器会对每个函数的每个参数执行这种隐式类型转换。但它只对函数参数表中列出的参数进行转换,决不会对成员函数所在的对象(即,成员函数中的*this指针所对应的对象)进行转换。这就是为什么这个语句可以工作:
  result = onehalf.operator*(2); // converts int -> rational
  而这个语句不行:
  result = 2.operator*(onehalf); // 不会转换
  // int -> rational
  第一种情形操作的是列在函数声明中的一个参数,而第二种情形不是。
  尽管如此,你可能还是想支持混合型的算术操作,而实现的方法现在应该清楚了:使operator*成为一个非成员函数,从而允许编译器对所有的参数执行隐式类型转换:
  class rational {
  ... // contains no operator*
  };
  // 在全局或某一名字空间声明,
  // 参见条款m20了解为什么要这么做
  const rational operator*(const rational& lhs,
  const rational& rhs)
  {
  return rational(lhs.numerator() * rhs.numerator(),
  lhs.denominator() * rhs.denominator());
  }
  rational onefourth(1, 4);
  rational result;
  result = onefourth * 2; // 工作良好
  result = 2 * onefourth; // 万岁, 它也工作了!
  这当然是一个完美的结局,但还有一个担心:operator*应该成为rational类的友元吗?
  这种情况下,答案是不必要。因为operator*可以完全通过类的公有(public)接口来实现。上面的代码就是这么做的。只要能避免使用友元函数就要避免,因为,和现实生活中差不多,友元(朋友)带来的麻烦往往比它(他/她)对你的帮助多。
  然而,很多情况下,不是成员的函数从概念上说也可能是类接口的一部分,它们需要访问类的非公有成员的情况也不少。
  让我们回头再来看看本书那个主要的例子,string类。如果想重载operator>>和operator<<来读写string对象,你会很快发现它们不能是成员函数。如果是成员函数的话,调用它们时就必须把string对象放在它们的左边:
  // 一个不正确地将operator>>和
  // operator<<作为成员函数的类
  class string {
  public:
  string(const char *value);
  ...
  istream& operator>>(istream& input);
  ostream& operator<<(ostream& output);
  private:
  char *data;
  };
  string s;
  s >> cin; // 合法, 但
  // 有违常规
  s << cout; // 同上
  这会把别人弄糊涂。所以这些函数不能是成员函数。注意这种情况和前面的不同。这里的目标是自然的调用语法,前面关心的是隐式类型转换。
  所以,如果来设计这些函数,就象这样:
  istream& operator>>(istream& input, string& string)
  {
  delete [] string.data;
  read from input into some memory, and make string.data
  point to it
  return input;
  }
  ostream& operator<<(ostream& output,
  const string& string)
  {
  return output << string.data;
  }
  注意上面两个函数都要访问string类的data成员,而这个成员是私有(private)的。但我们已经知道,这个函数一定要是非成员函数。这样,就别无选择了:需要访问非公有成员的非成员函数只能是类的友元函数。
  本条款得出的结论如下。假设f是想正确声明的函数,c是和它相关的类:
  ·虚函数必须是成员函数。如果f必须是虚函数,就让它成为c的成员函数。
  ·operator>>和operator<<决不能是成员函数。如果f是operator>>或operator<<,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。
  ·只有非成员函数对最左边的参数进行类型转换。如果f需要对最左边的参数进行类型转换,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。
  ·其它情况下都声明为成员函数。如果以上情况都不是,让f成为c的成员函数。
  回答者:Dyemn - 高级经理 六级 12-27 08:29
  友元函数要在一个类体内说明,形式为:
  friend 类型名 友元函数名(形参表);
  然后在类体外对友元函数进行定义,定义的格式和普通函数相同,但可以通过对象作为参数直接访问对象的私有成员
  友元函数说明如下:
  1)必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型,友元函数的说明可以出现在类的任何地方,包括在private和public部分;
  2)注意友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用"::"指示属于哪个类,只有成员函数才使用"::"作用域符号;
  3)友元函数不能直接访问类的成员,只能访问对象成员,
  4)友元函数可以访问对象的私有成员,但普通函数不行;
  5)调用友元函数时,在实际参数中需要指出要访问的对象,
  6)类与类之间的友元关系不能继承。
luojc714 2008-11-20
  • 打赏
  • 举报
回复
学习了!
2楼的讲得蛮好的!
加载更多回复(22)

65,210

社区成员

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

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