对友元的理解

本文详细介绍了C++中的友元机制,包括友元函数和友元类的概念及其作用。友元允许外部函数或类访问通常受限的私有和保护成员,从而打破封装性。通过友元,程序员可以灵活地设计类之间的交互,但需谨慎使用以保持代码的清晰和安全性。示例代码展示了如何声明和使用友元函数以及成员函数作为友元的情况。
摘要由CSDN通过智能技术生成

一、友元

   在类里面有公有成员,私有成员,保护成员。
公有成员:是既可以在类外访问也可以在类里访问
私有成员:需要该类的成员函数才能对私有成员的访问
  但如果要通过一个函数去访问私有成员,但这个函数不属于该类里面的函数。
这就是"友元"起到作用**

C++不跟C一样,在C里面定义的数据,没有访问规则,可以直接去访问它,但是在C++这门语言里面定义了各种访问权限规则,什么时候可以去访问这个数据,什么时候又不能去访问这个数据这些都有规定,这样使得数据更安全,不容易被破坏,这就是C++其中的封装特性

而友元呢,破坏了这种数据的隐藏,隐蔽性的特点,数据都是被隐藏在一个安全的地方,而友元就相当于在这个很安全的地方装了一扇窗子,可以通过这扇窗子进去,访问这个数据。

二、友元函数

友元函数示例:

#include <iostream>
using namespace std;
class Point
{
public:
	friend Point middle(const Point& a, const Point& b);  //声明middle是Point类的友元函数
	Point(float a, float b)  : x(a), y(b) {}
	void printf()
	{
		cout << "中点坐标:" << x << "," << y << endl;
	}
private:
	float x;
	float y;
};
//通过middle函数可以直接访问private里面的数据
//middle这个函数不属于任何类的成员函数
Point middle(const Point& a, const Point& b)
{
	Point c((a.x + b.x) / 2, (a.y + b.y) / 2);
	return c;
}
int main(int argc, char* argv[])
{
	Point a(1, 5);
	Point b(2, 7);
	middle(a, b).printf();
	return 0;
}

如果想在类外去访问该类的private数据成员,就得声明该类外的函数是该类的友元函数,通过声明后的友元函数才能对该类的私有成员进行访问。

举个现实生活的例子:
友元友元不就是朋友的关系嘛,我想去你家里面玩,陌生人让进嘛?肯定不让进,去你家玩,肯定是朋友的关系,在这里Point这个类就相当于你的家,middle这个函数相当于这个人,还要知道middle这个人到底是朋友呢还是陌生人呢,就取决于他是否声明的友元,声明了就是朋友,没有声明就是陌生人。

三、一个类的成员函数是另外一个类的友元

#include <iostream>
#include <cstring>
#pragma warning(disable : 4996 26432 26401 26409 26440 26485 4150)
using namespace std;
class Person;

class Spouse
{
public:
	Spouse(const Person& Phu, const Person& Pw);
	~Spouse() { delete Phusband; delete Pwife; }
	void Show() const;
private:
	Person* Phusband;
	Person* Pwife;
};

class Person
{
public:
	friend void Spouse::Show() const;   //声明Spouse类中的Show成员函数是Persou类的友元函数
	Person(const char* nm, int ag, const char* sx) : age(ag) {
		strcpy(name, nm);
		strcpy(sex, sx);
	}
	void Show()
	{
		cout << name << " " << age << " " << sex << endl;
	}

private:
	char name[10];
	int age;
	char sex[10];
};

Spouse::Spouse(const Person& Phu, const Person& Pw)
{
	Phusband = new Person(Phu);
	Pwife = new Person(Pw);
}

void Spouse::Show() const
{
	cout << "丈夫:" << Phusband->name << " " << Phusband->age << " " << Phusband->sex << endl;
	cout << "妻子:" << Pwife->name << " " << Pwife->age << " " << Pwife->sex << endl;
}

int main()
{
	Person hus("胡强", 33, "男");
	Person wf("小风", 32, "女");
	Spouse sp(hus, wf);

	hus.Show();
	wf.Show();
	sp.Show();
	
	system("pause");
	return 0;
}

定义了两个类Spouse和Persou
在类Spouse前面引用了class Person,因为类Spouse需要用到类Person,而Person在Spouse的后面
为了解决这个问题,所以在类Spouse前面引用类Serson.
但注意的是:类提前声明使用的范围是有限的,只有正式声明一个类才能去定义这个类的对象,在类Spouse中数据成员不能直接定义为Persou类的对象
改为:
Persou Phusband;
Persou Pwife;
就会报错,这是因为正式声明一个类之前,编译器无法确定Persou类需要多大的内存空间,所以对一个类做了提前引用声明后,可以用该类的名字去指向该类的指针变量或对象的引用。因为指针变量和引用本身的大小是固定的。

这个代码是将Spouse类的成员函数show()
作为Persou的友元函数,那么可以通过Spouse类中的show()去访问Persou中的数据成员

四、友元类

#include <iostream>
#include <cstring>
#pragma warning(disable : 26440 26485 26496 4996 4150 26432 26401 26409)
using namespace std;
class Person;

class Spouse
{
private:
	Person* pHusband;
	Person* pWife;
public:
	Spouse(const Person& hus, const Person& wf);
	~Spouse() { delete pHusband; delete pWife; }
	void Show() const;
};

class Person
{
private:
	char name[10];
	int age;
	char sex[10];

public:
	friend class Spouse; //声明Phusband是Pwife友元类
	Person(const char* nm, const int ag, const char* se) : age(ag)
	{
		strcpy_s(name, nm);
		strcpy_s(sex, se);
	}
	void Show() const
	{
		cout << name << " " << age << " " << sex << endl;
	}
};

Spouse::Spouse(const Person& hus, const Person& wf)
{
	pHusband = new Person(hus);
	pWife = new Person(wf);
}

void Spouse::Show() const
{
	cout << "丈夫: " << pHusband->name << " " << pHusband->age << " " << pHusband->sex << endl;
	cout << "妻子: " << pWife->name << " " << pWife->age << " " << pWife->sex << endl;
}

int main()
{
	Person huf("张强", 18, "男");
	Person wf("小丽", 17, "女");
	Spouse sp(huf, wf);

	huf.Show();
	wf.Show();
	sp.Show();
	system("pause");
	return 0;
}

如果把以上代码改为:

#include <iostream>
#include <cstring>
#pragma warning(disable : 26440 26485 26496 4996 4150 26432 26401 26409)
using namespace std;
class Spouse;
class Person
{
private:
	char name[10];
	int age;
	char sex[10];

public:
	friend class Spouse; //声明Phusband是Pwife友元类
	Person(const char* nm, const int ag, const char* se) : age(ag)
	{
		strcpy_s(name, nm);
		strcpy_s(sex, se);
	}
	void Show() const
	{
		cout << name << " " << age << " " << sex << endl;
	}
};

class Spouse
{
private:
	Person pHusband;
	Person pWife;
public:
	Spouse(const Person& hus, const Person& wf) : pHusband(hus), pWife(wf) {}
	
	void Show() const;
};


void Spouse::Show() const
{
	cout << "丈夫: " << pHusband.name << " " << pHusband.age << " " << pHusband.sex << endl;
	cout << "妻子: " << pWife.name << " " << pWife.age << " " << pWife.sex << endl;
}

int main()
{
	Person huf("张强", 18, "男");
	Person wf("小丽", 17, "女");
	Spouse sp(huf, wf);

	huf.Show();
	wf.Show();
	sp.Show();
	system("pause");
	return 0;
}

让Person类在Spouse类的前面 那么在Spouse类中可以直接定义对象
Person pHusband;
Person pWife;

先声明Person类,才能知道Person这个类的大小,才能在Spouse类中定义Person类的对象,编译器才能知道具体要分配多大的内存空间
如果将friend class Spouse改为:
friend void Spouse:: Show() const;

编译器会报错,由于先定义的是Person类,后定义的是Spouse类,如果在先声明的Person类中定义一个Spouse类中的Show函数是Person的友元, 编译器找不到Spouse类中是否存在Show这样的一个函数。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值