C++笔记(十八)——友元

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37764129/article/details/85053016

一、友元的产生条件:

  • 类的主要特点之一是数据隐藏,即类的私有成员只能在类定义的范围内使用,也就是说私有成员只能通过它的成员函数来访问
  • 但是,有时候需要在类的外部访问类的私有成员。为此,就需要寻找一种途径,在不放弃私有数据安全性的情况下,使得类外部的函数或类能够访问类中的私有成员——友元

注:

  • 友元相当于一扇通往私有成员的后门
  • 友元是外部的函数,它可分为:友元函数,友元成员,友元类

二、说明

友元的缺点: 破坏了函数的封装性

2.1 普通函数作为友元

      友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但它可以访问该类的所以对象的成员,包括私有成员和公有成员。

        在类定义声明友元函数时,需在其函数名前上关键字friend函数名后的括号内要加类名及类的对象。此声明可以放在公有部分,也可以放在私有部分。友元函数可以定义在类的内部,也可以定义在类的外部。

#include <iostream>
#include <string>

using namespace std;

class CString
{
	char *str;
public:
	CString(char *str)
	{
		cout << "构造CString " << endl;
		this->str = new char[strlen(str) + 1];
		strcpy(this->str, str);
	}
	~CString()
	{
		cout << "析构CString" << endl;
		delete[] str;
	}
	void print()
	{
		cout << "CString: " << str << endl;
	}

	friend void my_print(CString &ob); //定义友元函数,括号中加要连接的类的实例化对象
};

void my_print(CString &ob)
{
	cout << "--------------" << endl;
	cout <<"通过友元my_print访问私有数据: " << ob.str << endl; //通过友元访问私有数据
	ob.print();//访问公有信息
}

int main()
{
	{
		CString ob1("Chen Xingwei");
		ob1.print();
		my_print(ob1);
	}

	getchar();
	return 0;
}

注:

  • 友元函数虽然可以访问类对象的私有成员,但它毕竟不是成员函数。因此,在类的外部定义友元函数时,不必像成员函数那样,在函数名前加上“类名::”
  • 友元函数一般带有一个该类的入口参数(当前类名 &实例化的对象名)。因为友元函数不是类的成员,所以它不能直接引用对象成员的名称,也不能通过this指针引用对象的成员,它必须通过作为入口参数传递进来的对象名或对象指针来引用该对象的成员。
  • 一个函数需要访问多个类时友元函数非常有用,普通的成员函数只能访问其所属的类,但是多个类的友元函数能够访问相应的所有类的数据
  • 友元函数通过直接访问对象的私有成员,提高了程序运行的效率。在某些情况下, 如运算符被重载时,需要用到友元。但是友元函数破坏了数据的隐蔽性,降低了程序的可维护性,这与面向对象的程序设计思想是背道而驰的,因此使用友元函数应谨慎

2.2 类的成员函数作为友元

        除了一般的函数可以作为某个类的友元外,一个类的成员函数也可以作为另一个类的友元,这种成员函数不仅可以访问自己所在类对象中的私有成员和公有成员,还可以访问friend声明语句所在类对象中的私有成员和公有成员,这样能使两个类相互合作、协调工作,完成某一任务

#include <iostream>
#include <string>
class CBoy; //向前声明
using namespace std;

class CGirl
{
private:
	char m_name[64];
	int m_age;
public:
	CGirl(char *m_name, int age)
	{
		strcpy(this->m_name, m_name);
		this->m_age = age;
	}
	void girl_print(CBoy &ob); //友元,访问CBoy
};

class CBoy
{
private:
	char m_name[64];
	int m_age;
public:
	CBoy(char *m_name, int age)
	{
		strcpy(this->m_name, m_name);
		this->m_age = age;
	}
	friend void CGirl::girl_print(CBoy &ob);
};

void CGirl::girl_print(CBoy &ob) //友元,访问CBoy
{
	cout << "girl.name = " << m_name << endl;
	cout << "girl.age = " << m_age << endl;
	cout << "boy.name = " << ob.m_name << endl;
	cout << "boy.age = " << ob.m_age << endl;
}

int main()
{
	{
		CBoy Bob((char *)"Bob", 22);
		CGirl Lucy((char*)"Lucy", 15);
		Lucy.girl_print(Bob); //先调用girl类,再通过友元调boy类,然而girl在boy下面,所以需要先声明
	}
	
	getchar();
	return 0;

}

说明:

  • 一个类的成员函数作为另一个类的友元函数时,必须先定义这个类。例如上例中,类CGirl的成员函数为类CBoy的友元函数,必须先定义类CGirl。并且在声明友元函数时,要加上成员函数所在类的类名,如:
friend void CGirl::girl_print(CBoy &对象名);
  • 程序中还要使用“向前引用”(引用添加了友元函数的那个类,这里是CBoy),因为函数girl_print()中将“CBoy &对象名”作为参数,而CBoy要晚一些时候才定义

2.3 友元类

    不仅函数可以作为一个类的友元,一个类也可以作为另一个类的友元。这种友元类的声明方法是在另一个类声明中加入语句“friend 类名;”,其中的“类名”即为友元类的类名。此语句可以放在公有部分也可以放在私有部分。

class Y
{
  //.....
};

class X
{
  //...
  friend Y;
  //...
};

当一个类被声明为另一个类的友元时,它的所以的成员函数都成为另一个类的友元函数,这就意味着为友元的类中的所有成员函数都可以访问另一个类的私有成员。

注:

  • 友元关系是单向的,不具有交换性(我是你的朋友,不能推断出你是我的朋友)
  • 友元关系也不具有传递性(我是你的朋友,你是他的朋友,不能推断出:我是他的朋友)

猜你喜欢

转载自blog.csdn.net/qq_37764129/article/details/85053016