3.8  友元:友元函数和友元类

友元函数 :既可以是不属于任何类的非成员函数,也可以是另一个类的成员函数,统称为友元函数。友元函数不是当前类的成员函数,而是独立于类的外部函数,但它可以访问该类所有的成员,包括私有成员、保护成员和公有成员。在类中声明友元函数时,需在其函数名前加上关键字friend,此声明可以放在公有部分、也可以放在保护和私有部分。友元函数可以定义在类部,也可以定义在类的外部。

3.8.1 将非成员函数声明为友元函数

//1、将非成员函数声明为友元函数
// 例3.33 友元函数的使用
#include<iostream>
using namespace std;
class Gril{public:Gril(char* n,int a){name = new char[strlen(n)+1];strcpy(name,n);age = a;}~Gril(){delete []name;}friend void display(Gril &);//声明友元函数    //friend void display(Gril );private:char* name;int age;
};
void display(Gril &x) //形参是对象的引用           //void display(Gril x) //形参是对象
{cout<<"女孩的姓名是:"<<x.name<<","<<"年龄:"<<x.age<<endl;
}
int main()
{Gril g("小丽",20);display(g);    //调用友元函数,实参是对象的引用 return 0;
}/*说明:1、友元函数虽然可以访问类对象的私有成员,但它毕竟不是成员函数,因此,在类的外部定义友元函数时,不必像成员函数那样,在函数名前加 "类名::"2、因为友元函数不是类的成员,所以它不能直接访问对象的数据成员,也不能通过this指针访问对象的数据成员,它必须通过作为入口参数传递进来的对象名(或对象指针、对象引用)来访问引用对象的数据成员。3、由于函数display是Gril类的友元函数,所以display函数可以访问Gril中私有数据成员
name、age。但是,在它们之前必须加上 "对象名."
*/

例1:非成员友元函数

/*
需求:例如有两个类Gril和Boy,现要求打印所有的男生和女生的名字和年龄,我们只需一个
独立的函数print就能完成,但它必须同时定义为这两个类的友元函数。
*/
//例如3.34   一个函数定义同时定义为两个类的友元函数
#include<iostream>
using namespace std;
class Boy;      //对Boy类的提前引用声明
class Gril{public:Gril(char N[],int A){strcpy(name,N);age = A;}friend void print(Gril &x)   //声明print函数是Gril类的友元函数
     {cout<<"女孩的姓名是:"<<x.name<<"  "<<"年龄:"<<x.age<<endl;}private:char name[20];int age;
};
class Boy{     //声明Boy类 public:Boy(char N[],int A){strcpy(name,N);age = A;}friend void print(Boy &y)    //声明print函数是Boy类的友元函数
     {cout<<"男孩的姓名是:"<<y.name<<"  "<<"年龄:"<<y.age<<endl;}private:char name[20];int age;
};
int main()
{Gril g1("王萌",12);   //定义Gril类对象g1 Gril g2("李芳",14);   //定义Gril类对象g2Gril g3("张丽",18);   //定义Gril类对象g3
  Boy  b1("张三",11);   //定义Boy类对象b1Boy  b2("李四",19);   //定义Boy类对象b2Boy  b3("王武",13);   //定义Boy类对象b3
  print(g1); //调用友元函数,实参是Gril对象g1 print(g2); //调用友元函数,实参是Gril对象g2print(g3); //调用友元函数,实参是Gril对象g3
  print(b1); //调用友元函数,实参是Boy对象b1print(b2); //调用友元函数,实参是Boy对象b2print(b3); //调用友元函数,实参是Boy对象b3return 0;
} 

例2:非成员友元函数

#include<iostream>
using namespace std;
class Boy;      //对Boy类的提前引用声明
class Gril{public:Gril(char N[],int A){strcpy(name,N);age = A;}friend void print(Gril &,Boy &);   //声明print函数是Gril类的友元函数 private:char name[20];int age;
};
class Boy{     //声明Boy类 public:Boy(char N[],int A){strcpy(name,N);age = A;}friend void print(Gril &,Boy &);    //声明print函数是Boy类的友元函数private:char name[20];int age;
};
void print(Gril &x,Boy &y)               //定义print有元函数
{cout<<"女孩的姓名是:"<<x.name<<"  "<<"年龄:"<<x.age<<endl;cout<<"男孩的姓名是:"<<y.name<<"  "<<"年龄:"<<y.age<<endl;
}
int main()
{Gril g1("王萌",12);   //定义Gril类对象g1 Gril g2("李芳",14);   //定义Gril类对象g2Gril g3("张丽",18);   //定义Gril类对象g3
  Boy  b1("张三",11);   //定义Boy类对象b1Boy  b2("李四",19);   //定义Boy类对象b2Boy  b3("王武",13);   //定义Boy类对象b3
  print(g1,b1); //调用友元函数,实参是Gril对象g1,Boy对象b1print(g2,b2); //调用友元函数,实参是Gril对象g2,Boy对象b2print(g3,b3); //调用友元函数,实参是Gril对象g3,Boy对象b3return 0;
} 

3.8.2将成员函数声明为友元函数
除了一般的非成员函数可以作为某个类的友元外,一个类的成员函数也可以作为另一个类的友元,它是友元函数中的一种,成为友元成员函数。友元成员函数不仅可以访问自己所在类对象中的私有成员和公有成员,还可以访问friend声明语句所在类对象中的所有成员。

例3.35 一个类的成员函数作为另一个类的友元函数

#include<iostream>
#include<string>
using namespace std;
class Gril;  //对类Gril提前引用声明
class Boy{public:Boy(char* n,int a){name = new char[strlen(n)+1];strcpy(name,n);age = a;}void disp(Gril );  //声明函数dis为类Boy为成员函数 ~Boy(){delete []name;}private:char* name;int age;
};
class Gril{public:Gril(char* n,int a){name = new char[strlen(n)+1];strcpy(name,n);age = a;}friend void Boy::disp(Gril );  //声明类Boy成员函数dis为类Gril的友元函数 ~Gril(){delete []name;}private:char* name;int age;
};
void Boy::disp(Gril x)                //定义类Boy的成员函数disp,同时也为类Gril的友元函数,
{                                      //形参为Gril类对象 cout<<"男孩的姓名:"<<name<<endl;  //函数disp作为Boy类的成员函数 ,可以访问Boy类对象的私有成员 cout<<"男孩的年龄:"<<age<<endl;   //注释同上 cout<<"女孩的姓名:"<<x.name<<endl;//函数disp作为Gril类的友元函数,可以访问Gril类对象的私有成员cout<<"女孩的年龄:"<<x.age<<endl; //注释同上
}
int main()
{Boy b("陈大林",11);Gril g("张晓好",12);b.disp(g);//调用Boy类的对象b的成员函数和Gril类的友元函数disp,实参是Gril类的对象g //因为函数disp是Boy类的成员函数,所以无需通过传递对象,可以直接访问自己的私有数据成员 return 0;
} 

3.8.3 友元类

不仅函数可以作为一个类的友元,一个类也可以作为另一个类的友元,称为友元类。友元类
的说明方法是在另一个类声明中加入语句。
friend class 类名;

此类名是友元类的类名。这条语句可以放在公有部分,也可以放在私有部分。例如,

class Y{
      ...
};
class X{
      ...
friend class Y; //声明类Y是类X的友元类
      ...
};

当类Y被说明类X的友元时,类Y的所有成员函数都成为类X的友元函数,这就意味着作为
友元类Y中的所有成员函数都可以访问类X中的所有成员(包括私有成员)。

下面的例子中,声明了两个类Boy和Gril,类Boy声明为类Gril的友元,因此类Boy的成员
函数都能成为类Gril的友元函数,它们都可以访问类Gril的私有成员。

例 3.36 友元类的应用

#include<iostream>
#include<string>
using namespace std;
class Gril;           //对友元类的提前引用声明
class Boy{public:Boy(char* n,int a){name=new char[strlen(n)+1];strcpy(name,n);age = a;} ~Boy(){delete []name;}void display1(Gril &);   //声明函数display1为类Boy的成员函数 void display2(Gril &);   //声明函数display2为类Boy的成员函数private:char* name;int age;
};
class Gril{public:Gril(char* n,int a){name=new char[strlen(n)+1];strcpy(name,n);age = a;} ~Gril(){delete []name;}     friend class Boy;    //声明Boy为类Gril的友元类,则类Boy中的所有成员函数为Gril类的友元成员函数          private:char* name;int age;
};
void Boy::display1(Gril &x)
{cout<<"男孩的姓名是:"<<name<<endl;cout<<"女孩的姓名是:"<<x.name<<endl;
} void Boy::display2(Gril &x)
{cout<<"男孩的年龄是:"<<age<<endl;cout<<"女孩的年龄是:"<<x.age<<endl;
}
int main()
{Boy b("陈大林",11);Gril g("张晓好",12);b.display1(g);b.display2(g);return 0;
} 

注意:声明一个类A为另一个类B的友元类(则类A的所有成员函数都是类B的友元函数,友元类A的所有成员函数既可以访问自己本类的所有成员,也可以访问类B的所有成员)

#include<iostream>
#include<string>
using namespace std;
class Gril;           //对友元类的提前引用声明
class Boy{public:Boy(char* n,int a){name=new char[strlen(n)+1];strcpy(name,n);age = a;} ~Boy(){delete []name;}void display(Gril &);   //声明函数display为类Boy的成员函数 private:char* name;int age;
};
class Gril{public:Gril(char* n,int a){name=new char[strlen(n)+1];strcpy(name,n);age = a;} ~Gril(){delete []name;}     friend class Boy;    //声明Boy为类Gril的友元类,则类Boy中的所有成员函数为Gril类的友元成员函数          private:char* name;int age;
};
void Boy::display(Gril &x)
{cout<<"男孩的姓名是:"<<name<<endl;cout<<"男孩的年龄是:"<<age<<endl;cout<<"女孩的姓名是:"<<x.name<<endl;cout<<"女孩的年龄是:"<<x.age<<endl;
}
int main()
{Boy b("陈大林",11);Gril g("张晓好",12);b.display(g);return 0;
} /*说明:友元关系是单向的,不具有交换性。若声明了类X是类Y的友元类(即在类Y定义中声明X为friend类),不等于类Y一定是X的友元,这就要看在类X中是否有相应的声明。友元关系也不具有传递性,若类X是类Y的友元,类Y是类Z的友元,不一定类X是类Z的友元。如果想让类X是类Z的友元类,应在类Z中作出声明。
*/

转载于:https://www.cnblogs.com/XYQ-208910/p/4912261.html

C++:友元(非成员友元函数、成员友元函数、友元类)相关推荐

  1. 理解数据成员指针、函数成员指针

    转自:http://www.cnblogs.com/malecrab/p/5572119.html 1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针. 而对于数据成员指针变 ...

  2. 将类的成员函数作为回调函数(外一篇:友元函数)

    转自:http://blog.csdn.net/xylary/article/details/1548596 将类成员函数用做C回调函数 提出问题:  回调函数是基于C编程的Windows SDK的技 ...

  3. C++——运算符的重载---以成员函数方式重载---以友元函数方式重载

    一.运算符的重载 1.运算符的重载 允许把标准运算符(如+ - * /等运算符)应用于自定义数据类型的对象,可以提高程序的可读性,运算符的重载本质上还是函数重载.运算符仅仅是语法上的方便,它是另一种函 ...

  4. 第七周项目一-成员函数、友元函数和一般函数有区别(1)

     /**Copyright(c)2016,烟台大学计算机与控制工程学院*All rights reserved*文件名称:123.cpp*作 者:王蕊*完成日期:2016年4月12日*版 本 号: ...

  5. 模板类中使用友元函数的方式,派生类友元函数对基类的成员使用情况

    在一般友元函数的前面加上 template<typename T),注意在函数的声明和定义处都要加这个模板 例如: //模板类,长方体类 template <typename Elemen ...

  6. 拷贝构造,深度拷贝,关于delete和default相关的操作,explicit,类赋初值,构造函数和析构函数,成员函数和内联函数,关于内存存储,默认参数,静态函数和普通函数,const函数,友元

     1.拷贝构造 //拷贝构造的规则,有两种方式实现初始化. //1.一个是通过在后面:a(x),b(y)的方式实现初始化. //2.第二种初始化的方式是直接在构造方法里面实现初始化. 案例如下: ...

  7. C++模板学习02(类模板)(类模板语法、类模板与函数模板的区别、类模板中的成员函数创建时机、类模板对象做函数参数、类模板与继承、类模板成员函数类外实现、类模板分文件编写、类模板与友元)

    C++引用详情(引用的基本语法,注意事项,做函数的参数以及引用的本质,常量引用) 函数高级C++(函数的默认参数,函数的占位参数,函数重载的基本语法以及注意事项) C++类和对象-封装(属性和行为作为 ...

  8. 0710学习总结(友元函数,string函数,引用)

    一.友元函数 友元函数在当前类外定义,不属于当前类的函数,要加上friend. 友元函数不属于任何类的非成员函数,也可以是其他类的 代码: #include <iostream> usin ...

  9. c语言的友元函数的用法,C++友元函数和友元类概念解析

    一.友元函数 友元函数是一种特殊的函数,它需要在类体内进行说明,可以访问类的私有成员和保护成员,但又不是类的成员函数.友元函数的说明如下: friend 数据类型函数名(参数) 其中,friend是说 ...

  10. 友元函数、类的非静态成员函数、静态成员函数的区别

    类中申明的函数相对于类来说有三层意思: 1.有this指针 2.函数在类的作用区域中 3.可以访问类中私有部分 4.可以被继承 非静态成员函数具有1234 静态成员函数具有234 友元函数具有3 静态 ...

最新文章

  1. Linux 查看交换区内容,Unix: Unix/Linux/Win的虚拟交换区信息的查看
  2. 【Eclipse中使用Git之一】把远程仓库的项目,clone到eclipse里面
  3. Java学习第三天160818 表单 框架 下拉列表等
  4. tzwhere模块 根据经纬度判断时区
  5. (四)系统虚拟化关键技术
  6. 直播 | AAAI 2021:文本对抗攻防中的对抗训练方法
  7. FastReport.net 使用记录
  8. setTimeout里如果有$(this),$(this)指的是谁?
  9. php备份mysql页面_如何用PHP的页面备份、恢复Mysql数据库_php
  10. 从命令行获取两个路径名称并找出文件一样内容一样的两个文件
  11. ios sdk 穿山甲_GitHub - ArthurKnight/flutter_ad_pangolin_plugin: iOS flutter 穿山甲插件
  12. SourceInsight工程文件与源文件相对路径
  13. 怎么将表中的空格都转变为0???
  14. Python max函数中key的用法
  15. ZUC密码算法 - Python实现
  16. 网络爬虫js逆向解决网站登录RSA加密问题,不使用selenium如何实现登录,session维持登录状态请求爬取
  17. 重言式判别 (数据结构课程设计)
  18. 本科学经济还是学数学和计算机,如果考研想往经管类方向,学习数学类,还是数学与应用数学, 这两个专业有什么不同...
  19. 【​观察】解读微软物联网新价值观 三位一体释放“云+端”能量
  20. BPM软件_K2再度入选Gartner iBPMS MQ挑战者象限_全球领先的工作流引擎

热门文章

  1. 手把手教你如何写简历
  2. 大学的软件测试怎么学
  3. ORA-27041: unable to open file--恢复被rm意外删除数据文件
  4. JAVA 中的数据结构
  5. Linux——入门基本命令
  6. oracle 表空间-用户-授权-表创建
  7. context:component-scan报错
  8. 我们越来越浮躁的心靠什么去滋润
  9. $git学习总结系列(4)——gitignore文件
  10. 一些有趣的三方开源库