文章预览:

  • 一. 前言
  • 二. 友元函数
  • 三. 友元类
  • 四. 友元成员函数



一. 前言

众所周知,C++控制对类对象私有成员的访问。通常,公有类方法(public)提供唯一的访问途径,但是有时候这种限制太严格,以至于不适合特定的编程问题。

在这种情况下,C++提供了另外一种形式的访问权限:友元,友元有3种:

  • 友元函数;
  • 友元类;
  • 友元成员函数;

优缺点

  • 优点:通过让函数成为类的友元(即:友元函数),可以赋予该函数与类的成员函数相同的访问权限,使其可以访问本类protected、private成员,在某些频繁访问成员变量的地方可以提高性能。
  • 缺点:友元破坏了面向对象的封装性。

二. 友元函数

1、通过friend将一个函数(友元函数是个函数)声明为某个类的友元函数,那么该函数就能访问这个类的所有成员(成员变量、成员函数),无论是public,private,protected

2、因为友元函数不属于类成员,所以其不受public/protected/private的限制,放在public/protected/private下声明都行。

代码展示

#include <iostream>
using namespace std;

class A
{
private:
	int data;

	void display(){
		cout << "data = " << data << endl;
	}

	friend void change(int x, A& a); // 将函数change()声明为类A的友元函数
};

void change(int x, A& a)
{
	a.data = x;
	a.display();
}

int main()
{
	A a;
	change(10, a);
	return 0;
}

三. 友元类

1、可以在类A中把类B声明为类A的友元类,此时,在类B(类A的友元类)的成员函数中,可以访问类A的所有成员(成员变量、成员函数),无论是public,private,protected

2、由于友元类不属于类成员,所以友元类的声明不受public、protected、private的影响。

代码展示Tip:为什么需要类B的声明):

#include <iostream>
using namespace std;

class B; // 类B的声明,类A用到了类B,而类B的定义有可能在类A的定义之后导致编译出错,所以最好先声明一下类B
class A
{
private:
	int data;

	void display()
	{
		cout << "data = " << data << endl;
	}

	friend class B; // 将类B声明为类A的友元类(用到了类B的名字,所以需要前面声明一下class B; )
};

class B
{
public:
	void change(int x, A& a)
	{
		a.data = x;  //在类B(类A的友元类)的成员函数中,可以访问类A的所有成员(成员变量、成员函数),无论是public,private,protected
		a.display();
	}
};

int main()
{
	A a;
	B b;
	b.change(50, a);

	return 0;
}

注意:每个类都负责控制自己的友元类和友元函数:

  • 友元关系不能被继承;
  • 友元关系是单向的,比如类B是类A的友元类,但这并不代表类A是类B的友元类;
  • 友元关系没有传递性,比如类B是类A的友元类,类C是类B的友元类,但这并不代表类C是类A的友元类;

四. 友元成员函数

友元成员函数:即是本类的成员函数,又是其他类的友元函数。

代码展示

A.h(Tip:为什么使用#include "B.h"而不用class B;声明类B

#ifndef __A_H
#define __A_H

#include <iostream>

//class B;   //注:声明友元成员函数不能仅仅使用类B的声明了,因为在friend void B::change(int x, A& a)不仅仅用到了类B的名字,
             //还用到了其成员函数change(),系统需要先判断类B中是否有其成员函数change(),所以需要用#include "B.h"
#include "B.h"
             
class A
{
private:
	int data;

	void display()
	{
	    std::cout << "data = " << data << std::endl;
	}

	friend void B::change(int x, A& a); // 该函数是友元成员函数的声明:将类B的成员函数change()声明为类A的友元函数
};

#endif

B.h

#ifndef __B_H
#define __B_H

class A; // 类A的声明

class B
{
public:
	void change(int x, A& a); // 只有public的成员函数才能成为其它类的友元函数
};

#endif

B.cpp

#include "A.h"
#include "B.h"

void B::change(int x, A& a)
{
	a.data = x;
	a.display();
}

main.cpp

#include "A.h"
#include "B.h"

int main()
{
	A a;
	B b;
	b.change(50, a);

	return 0;
}

下雨天,最惬意的事莫过于躺在床上静静听雨,雨中入眠,连梦里也长出青苔。