友元函数和友元类在实际开发中较少使用,想快速学习C++的读者可以跳过本节。

一个类中可以有 public、protected、private 三种属性的成员,通过对象可以访问 public 成员,只有本类中的函数可以访问本类的 private 成员。现在,我们来补充介绍一个例外——友元(friend)。

在C++中,这种关系以关键宇 friend 声明,中文多译为友元。友元可以访问与其有好友关系的类中的私有成员,友元包括友元函数和友元类。如果您对友元这个名词不习惯,可以按原文 friend 理解为朋友即可。

友元函数

在当前类以外定义的、不属于当前类的函数也可以在类中声明,但要在前面加 friend 关键字,这样就构成了友元函数。友元函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。

友元函数可以访问当前类中的所有成员,包括 private 属性的。

1) 将普通函数声明为友元函数。

  1. #include<iostream>
  2. using namespace std;
  3. class Student{
  4. private:
  5. char *name;
  6. int age;
  7. float score;
  8. public:
  9. Student(char*, int, float);
  10. friend void display(Student &); //将display声明为友元函数
  11. };
  12. Student::Student(char *name, int age, float score){
  13. this->name = name;
  14. this->age= age;
  15. this->score = score;
  16. }
  17. //普通成员函数
  18. void display(Student &stu){
  19. cout<<stu.name<<"的年龄是 "<<stu.age<<",成绩是 "<<stu.score<<endl;
  20. }
  21. int main(){
  22. Student stu("小明", , 95.5f);
  23. display(stu);
  24. return ;
  25. }

请注意 display 是一个在类外定义的且没有使用 Student 作限定的函数,它是非成员函数,不属于任何类,它的作用是输出学生的信息。如果在 Student 类中未声明 display 函数为 friend 函数,它是不能引用 Student 中的私有成员 name、age、score 的。

现在由于声明了 display 是 Student 类的 friend 函数,所以 display 可以使用 Student 中的私有成员 name、age、score。但注意在使用这些成员变量时必须加上对象名,不能写成:

  1. cout<<name<<"的年龄是 "<<age<<",成绩是 "<<score<<endl;

因为 display 不是 Student 类的成员函数,默认不能使用 Student 类的成员,必须指定要访问的对象。

2) 将其他类的成员函数声明为友元函数
friend 函数不仅可以是普通函数(非成员函数),还可以是另一个类中的成员函数。请看下面的例子:

  1. #include<iostream>
  2. using namespace std;
  3. class Address; //对Address类的提前引用声明
  4. //声明Student类
  5. class Student{
  6. private:
  7. char *name;
  8. int age;
  9. float score;
  10. public:
  11. Student(char*, int, float);
  12. void display(Address &);
  13. };
  14. //声明Address类
  15. class Address{
  16. private:
  17. char *province;
  18. char *city;
  19. char *district;
  20. public:
  21. Address(char*, char*, char*);
  22. //将Student类中的成员函数display声明为友元函数
  23. friend void Student::display(Address &);
  24. };
  25. Address::Address(char *province, char *city, char *district){
  26. this->province = province;
  27. this->city = city;
  28. this->district = district;
  29. }
  30. //声明Student类成构造函数和成员函数
  31. Student::Student(char *name, int age, float score){
  32. this->name = name;
  33. this->age= age;
  34. this->score = score;
  35. }
  36. void Student::display(Address &add){
  37. cout<<name<<"的年龄是 "<<age<<",成绩是 "<<score<<endl;
  38. cout<<"家庭住址:"<<add.province<<"省"<<add.city<<"市"<<add.district<<"区"<<endl;
  39. }
  40. int main(){
  41. Student stu("小明", , 95.5f);
  42. Address add("陕西", "西安", "雁塔");
  43. stu.display(add);
  44. return ;
  45. }

在本例中定义了两个类 Student 和 Address。程序第 26 行将 Student 类中的成员函数 display 声明为友元函数,由此,display 就可以访问 Address 类的私有成员变量了。

两点注意:
① 程序第4行对Address类进行了提前声明,是因为在Address类定义之前、在Student类中使用到了它,如果不提前声明,编译会报错,提示"Address" has not been declared。类的提前声明和函数的提前声明是一个道理。

② 程序中将 Student 类的声明和定义分开了,而将 Address 放在了中间,是因为 Student::display() 函数体中用到了 Address 类的成员,必须出现在 Address 类的类体之后(类体说明了有哪些成员)

这里简单介绍一下类的提前声明。一般情况下,类必须在正式声明之后才能使用;但是某些情况下(如上例所示),只要做好提前声明,也可以先使用。

但是应当注意,类的提前声明的使用范围是有限的。只有在正式声明一个类以后才能用它去创建对象。如果在上面程序第4行后面增加一行:

在对一个类作了提前引用声明后,可以用该类的名字去定义指向该类型对象的指针变量或对象的引用变量(如在本例中,定义了Address类对象的引用变量)。这是因为指针变量和引用变量本身的大小是固定的,与它所指向的类对象的大小无关。

请注意程序是在定义 Student::display() 函数之前正式声明 Address 类的。这是因为在 Student::display() 函数体中要用到 Address 类的成员变量 province、city、district,如果不正式声明 Address 类,编译器就无法识别这些成员变量。

③ 一个函数可以被多个类声明为“朋友”,这样就可以引用多个类中的私有成员。

友元类

不仅可以将一个函数声明为一个类的“朋友”,而且可以将整个类(例如B类)声明为另一个类(例如A类)的“朋友”。这时B类就是A类的友元类。

友元类B中的所有函数都是A类的友元函数,可以访问A类中的所有成员。在A类的类体中用以下语句声明B类为其友元类:

  1. friend B;

声明友元类的一般形式为:

  1. friend 类名;

关于友元,有两点需要说明:

  • 友元的关系是单向的而不是双向的。如果声明了 B类是A类的友元类,不等于A类是B类的友元类,A类中的成员函数不能访问B类中的私有数据。
  • 友元的关系不能传递,如果B类是A类的友元类,C类是B类的友元类,不等于 C类是A类的友元类。

在实际开发中,除非确有必要,一般并不把整个类声明为友元类,而只将确实有需要的成员函数声明为友元函数,这样更安全一些。

C++学习12 友元函数和友元类的更多相关文章

  1. 友元(友元函数、友元类和友元成员函数) C++

    有些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,这是很方便做到的.例如被重载的操作符,如输入或输出操作符,经常需要访问类的私有数据成员. 友元(frend)机制允许一个类将 ...

  2. C++友元(友元函数、友元类和友元成员函数)

    友元(友元函数.友元类和友元成员函数) C++ 有些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,这是很方便做到的.例如被重载的操作符,如输入或输出操作符,经常需要访问类的私 ...

  3. C++:友元(非成员友元函数、成员友元函数、友元类)

    3.8  友元:友元函数和友元类 友元函数 :既可以是不属于任何类的非成员函数,也可以是另一个类的成员函数,统称为友元函数.友元函数不是当前类的成员函数,而是独立于类的外部函数,但它可以访问该类所有的 ...

  4. c++友元函数与友元类

    友元函数和友元类的需要: 类具有封装和信息隐藏的特性.只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的.非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这 ...

  5. C++ friend友元函数和友元类(转)

    一个类中可以有 public.protected.private 三种属性的成员,通过对象可以访问 public 成员,只有本类中的函数可以访问本类的 private 成员.现在,我们来介绍一种例外情 ...

  6. 2.19 C++友元函数和友元类

    参考: http://www.weixueyuan.net/view/6350.html 总结: 借助friend关键字将其声明为友元函数,结果,在display函数体内,我们就能访问private属 ...

  7. C++之友元函数和友元类

    通过friend关键字,我们可以将不属于当前类的一个函数在当前类中加以声明,该函数便可以成为当前类的友元函数. #include<iostream>using namespace std; ...

  8. C++中的友元函数和友元类

    C++中的友元函数主要应用于以下场景: 友元函数 第一种场景 代码中有一个全局函数,该函数想要去访问某个类的成员变量(该类的成员变量是private的,且该类并未提供任何获取获取私有成员变量的publ ...

  9. 【C++基础 05】友元函数和友元类

    友元是一种定义在类外部的普通函数或类,但它须要在类体内进行说明,为了与该类的成员函数加以差别,在说明时前面加以keywordfriend. 友元不是成员函数,可是它能够訪问类中的私有成员. 友元的作用 ...

随机推荐

  1. EDIUS分别输出视频和音频的教程

    使用EDIUS剪辑好视频之后渲染输出文件时,为什么视频和音频分别出,而不是一起呢?这个问题很可能会让一些新手困惑不已,到底是什么原因呢?又要如何设置才能让输出的文件视音频一体呢?下面,小编将来和大家探 ...

  2. asp.net中Cookie的用法【转】

    比如建立一个名为aspcn,值为灌水小鱼的cookie HttpCookie cookie = new HttpCookie["aspcn"];cookie.Value = &qu ...

  3. Externalizable接口 序列化

    Java默认的序列化机制非常简单,而且序列化后的对象不需要再次调用构造器重新生成,但是在实际中,我们可以会希望对象的某一部分不需要被序列化,或者说一个对象被还原之后, 其内部的某些子对象需要重新创建, ...

  4. eclipse下gradle配置

    eclipse下gradle配置 这可真麻烦啊,一个项目把java的东西学习完了!这不,刚弄完maven又来了个gradle. http://gradle.org/gradle-download 1. ...

  5. 每日学习心得:SQL查询表的行列转换/小计/统计(with rollup,with cube,pivot解析)

    2013-8-20 1.    SQL查询表的行列转换/小计/统计(with  rollup,with cube,pivot解析) 在实际的项目开发中有很多项目都会有报表模块,今天就通过一个小的SQL ...

  6. IOS开发-视频,音频,录音简单总结

    /***** * 1. 视频播放 * *  @格式:mp4 mov m4v m2v 3gp 3g2 * *  @系统框架使用:#import <MediaPlayer/MediaPlayer.h ...

  7. 06socket编程

    socket可以看成是用户进程与内核网络协议栈的编程接口. socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信. IPv4套接口地址结构通常也称为“网际套接字地址结构”,它 ...

  8. laravel5-目录结构分析

    laravel5-目录结构分析 (2016-01-21 11:24:03) 转载▼     一.环境配置: $ lsb_release -a No LSB modules are available. ...

  9. js常见数字处理整理

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  10. TMDS协议

    1 概述 1.1    连接结构 图1 TMDS连接结构 数据流中包含了像素和控制数据,发送器在任何给定的输入时钟周期,到底是编码像素数据还是控制数据取决于数据使能信号DE,DE有效时,指示像素数 据 ...