一个类中可以有 public、protected、private 三种属性的成员,通过对象可以访问 public 成员,只有本类中的函数可以访问本类的 private 成员。现在,我们来介绍一种例外情况——友元(friend)。借助友元(friend),可以使得其他类中的成员函数以及全局范围内的函数访问当前类的 private 成员

一.将全局函数声明为友元函数

例:

#include <iostream>
using namespace std; class Student{
public:
Student(char *name, int age, float score);
public:
friend void show(Student *pstu); //将show()声明为友元函数
private:
char *m_name;
int m_age;
float m_score;
}; Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ } // 全局函数
void show(Student *pstu){
cout<<pstu->m_name<<"的年龄是 "<<pstu->m_age<<",成绩是 "<<pstu->m_score<<endl;
} int main(){
Student stu("小明", , 90.6);
show(&stu); //调用友元函数
Student *pstu = new Student("李磊", , 80.5);
show(pstu); //调用友元函数 return ;
}

运行结果:

小明的年龄是 15,成绩是 90.6
李磊的年龄是 16,成绩是 80.5

注意:友元函数不同于类的成员函数,在友元函数中不能直接访问类的成员,必须要借助对象。下面的写法是错误的:

void show(){
cout<<m_name<<"的年龄是 "<<m_age<<",成绩是 "<<m_score<<endl;
}

二.将其它类的成员函数声明为友元函数

#include <iostream>
using namespace std; class Address; //提前声明Address类 //声明Student类
class Student{
public:
Student(char *name, int age, float score);
public:
void show(Address *addr);
private:
char *m_name;
int m_age;
float m_score;
}; //声明Address类
class Address{
private:
char *m_province; //省份
char *m_city; //城市
char *m_district; //区(市区)
public:
Address(char *province, char *city, char *district);
//将Student类中的成员函数show()声明为友元函数
friend void Student::show(Address *addr);
}; //实现Student类
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address *addr){
cout<<m_name<<"的年龄是 "<<m_age<<",成绩是 "<<m_score<<endl;
cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"区"<<endl;
} //实现Address类
Address::Address(char *province, char *city, char *district){
m_province = province;
m_city = city;
m_district = district;
} int main(){
Student stu("小明", , 95.5f);
Address addr("陕西", "西安", "雁塔");
stu.show(&addr); Student *pstu = new Student("李磊", , 80.5);
Address *paddr = new Address("河北", "衡水", "桃城");
pstu -> show(paddr); return ;
}

运行结果:

小明的年龄是 16,成绩是 95.5
家庭住址:陕西省西安市雁塔区
李磊的年龄是 16,成绩是 80.5
家庭住址:河北省衡水市桃城区

注意:

1.程序刚开始对Address类进行提前声明的意义在于:在Address类定义之前,在Student类中使用了它,如果不提前声明,编译器会报错:'Address' has not been declared'

2.程序将 Student 类的声明和实现分开了,而将 Address 类的声明放在了中间,这是因为编译器从上到下编译代码,show() 函数体中用到了 Address 的成员 province、city、district,如果提前不知道 Address 的具体声明内容,就不能确定 Address 是否拥有该成员(类的声明中指明了类有哪些成员)。

3.类的提前声明的使用范围是有限的,只有在正式声明一个类以后才能用它去创建对象。如果在上面程序的第4行之后增加如下所示的一条语句,编译器就会报错:

Address addr;  //企图使用不完整的类来创建对象

4. 一个函数可以被多个类声明为友元函数,这样就可以访问多个类中的 private 成员

三.友元类

可以将整个类声明为友元类,这样友元类中的所有成员函数都是另一个类的友元函数

修改上述代码:

#include <iostream>
using namespace std; class Address; //提前声明Address类 //声明Student类
class Student{
public:
Student(char *name, int age, float score);
public:
void show(Address *addr);
private:
char *m_name;
int m_age;
float m_score;
}; //声明Address类
class Address{
public:
Address(char *province, char *city, char *district);
public:
//将Student类声明为Address类的友元类
friend class Student;
private:
char *m_province; //省份
char *m_city; //城市
char *m_district; //区(市区)
}; //实现Student类
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address *addr){
cout<<m_name<<"的年龄是 "<<m_age<<",成绩是 "<<m_score<<endl;
cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"区"<<endl;
} //实现Address类
Address::Address(char *province, char *city, char *district){
m_province = province;
m_city = city;
m_district = district;
} int main(){
Student stu("小明", , 95.5f);
Address addr("陕西", "西安", "雁塔");
stu.show(&addr); Student *pstu = new Student("李磊", , 80.5);
Address *paddr = new Address("河北", "衡水", "桃城");
pstu -> show(paddr); return ;
}

将Student类声明为Address类的友元类的语句为:

friend class Student;

有的编译器也可以不写 class 关键字,不过为了增强兼容性还是建议写上。

注意:

1.友元的关系是单向的而不是双向的。如果声明了类 B 是类 A 的友元类,不等于类 A 是类 B 的友元类,类 A 中的成员函数不能访问类 B 中的 private 成员。

2.友元的关系不能传递。如果类 B 是类 A 的友元类,类 C 是类 B 的友元类,不等于类 C 是类 A 的友元类。

C++语言基础(15)-友元函数和友元类的更多相关文章

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

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

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

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

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

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

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

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

  5. C++学习12 友元函数和友元类

    友元函数和友元类在实际开发中较少使用,想快速学习C++的读者可以跳过本节. 一个类中可以有 public.protected.private 三种属性的成员,通过对象可以访问 public 成员,只有 ...

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

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

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

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

  8. 第二十三节:Java语言基础-详细讲解函数与数组

    函数 函数在Java中称为方法,在其他语言中可能称为函数,函数,方法就是定义在类中具有特定功能的程序.函数,在Java中可称为方法. 函数的格式: 修饰符 返回值类型 函数名(参数类型 参数1, 参数 ...

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

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

随机推荐

  1. JNI之数据类型

    1. JNIEnv 作用 JNIEnv 概念 : 是一个线程相关的结构体, 该结构体代表了 Java 在本线程的运行环境 ; JNIEnv 与 JavaVM : 注意区分这两个概念; -- JavaV ...

  2. SQL Server on Linux: How? Introduction: SQL Server Blog

    SQL Server Blog Official News from Microsoft’s Information Platform https://blogs.technet.microsoft. ...

  3. 支付宝签名验证实现-Delphi版

    支付宝签名验证实现-Delphi版 首先介结下支付宝签名验证流程: 一  支付宝密钥生成 支付宝提供秘钥生成工具https://docs.open.alipay.com/291/105971/ 用此下 ...

  4. ASP.NET MVC生命周期介绍(转)

    本文以IIS7中asp.net应用程序生命周期为例,介绍了asp.net mvc的生命周期. asp.net应用程序管道处理用户请求时特别强调"时机",对asp.net生命周期的了 ...

  5. IOS Vsync

    vsync count Don't Sync Application.targetFrameRate 设置FPS上限 Every Second VBlank 30 Every VBlank 60 An ...

  6. golang中的那些坑之迭代器中的指针使用

    今天在编写代码的时候,遇到了一个莫名其妙的错误,debug了半天,发现这是一个非常典型且易犯的错误.记之 示例代码: package main import "fmt" type ...

  7. More is better——并查集求最大集合(王道)

    Description Mr Wang wants some boys to help him with a project. Because the project is rather comple ...

  8. 【android相关】【问题解决】R.java文件丢失

    在进行android开发过程中,有时候,我们会遇到gen文件中R.java丢失的现象.重新build,或者clean工程,close并重新打开Project,但有时也没解决. 这可能是由于不小心把xm ...

  9. EffectManager

    using UnityEngine; using System.Collections; public class EffectManager : MonoBehaviour { public Ani ...

  10. 微信小程序页面跳转

    一:跳转的数据传递 例如:wxml中写了一个函数跳转: [html] view plain copy <view class="itemWeight" catchtap=&q ...