C++学习笔记16-类和对象-友元,以及类的定义和声明顺序问题

本文详细介绍了C++中的友元机制,包括全局函数作为友元、类作为友元以及成员函数作为友元的用法。通过友元,可以使得非成员函数或类能够访问其他类的私有和保护成员,增加了代码的灵活性。示例代码展示了如何声明和使用友元,帮助理解这一概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

16.0 前言

生活中你的家有客厅(Public),有你的卧室(Private),
客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去。
但是也有例外,你也可以允许你的好闺蜜好基友进去。
在程序里,有些私有属性也想让类外的一些特殊函数或者类进行访问, 就需要用到友元的技术。
友元的目的就是让一个函数或者类访问另一个类中私有成员。
友元的关键字为friend
友元的三种实现:

  1. 全局函数做友元
  2. 类做友元
  3. 成员函数做友元

16.1 全局函数做友元

在全局函数中调用哪个类的私有成员,就使用关键字friend将此函数在那个类中声明即可。
语法:

friend 函数名(参数列表);

示例:

#include<iostream>
using namespace std;

class Building
{
	friend void goodGay2(Building& building);  //声明此全局函数是一个友元
public:
	Building()   
	{
		m_SittingRoom = "客厅";
		m_Bedding = "卧室";
	}
public:
	string m_SittingRoom; //客厅

private:
	string m_Bedding;    //卧室
};

//全局函数
void  goodGay(Building& building)
{
	cout << "好基友全局函数正在访问:" << building.m_SittingRoom << endl;
	//cout << "好基友全局函数正在访问:" << building.m_Bedding << endl;  无法访问私有成员的
}
void  goodGay2(Building& building)
{
	cout << "好基友全局函数正在访问:" << building.m_SittingRoom << endl;
	cout << "好基友全局函数正在访问:" << building.m_Bedding << endl;  //因为被声明了,所以可以访问
}

void test01()
{
	Building building;
	goodGay(building);
	goodGay2(building);
}
int main()
{
	test01();
	system("pause");
	return 0;
}

16.2 类做友元

在A类中调用B类的私有成员,就使用关键字friend将A类在B类中声明即可。
语法:

friend class 类名;

示例:

#include<iostream>
using namespace std;

//这里使用另外一种函数的写法
//函数声明在类中,在类外定义,只要在全局区写就可以,需要指出函数的所属域(属于哪个类)

class Building2 
{
	friend class GoodGay; //声明GoodGay 是Building2 的一个友元类
public:
	Building2();
	string m_SettingRoom;
private:
	string m_BedRoom;
};

class GoodGay
{
public:
	void visit();       //参观函数,访问Building2中的属性
	GoodGay();
	Building2* building;  //building是一个指针
};

Building2::Building2()
{
	m_SettingRoom = "客厅";
	m_BedRoom = "卧室";
}

void GoodGay::visit()
{
	cout << "好基友类正在访问:" << building->m_SettingRoom << endl;
	cout << "好基友类正在访问:" << building->m_BedRoom << endl;
}
GoodGay::GoodGay()
{
	//创建一个建筑物的对象
	building = new Building2;  //从而调用Building2的构造函数
}
void test2()
{
	GoodGay gg;
	gg.visit();
}
int main()
{
	test2();
	system("pause");
	return 0;
}

16.3 成员函数做友元

有时, 我们并不想使整个类A都成为类B的友元, 而是仅仅想使A类中的某个成员函数成为B类的友元, 这时可以在B类中使用下面的语法:
语法:

friend A::函数名(参数列表);

示例:

#include<iostream>
using namespace std;

class Building3;
class GoodGay2
{
public:
	GoodGay2();
	void visit();  //使visit可以访问Building3中的成员
	void visit2(); //visit2不可以访问Building3中的成员
	Building3* building;
};
class Building3
{
	friend void GoodGay2::visit(); //要声明visit()是友元,必须将它定义在上面
public:
	Building3();
	string settingRoom;
private:
	string BedRoom;
};
Building3::Building3()
{
	this->settingRoom = "客厅";
	this->BedRoom = "卧室";
}

GoodGay2::GoodGay2()   //创建一个对象, 和实例化是相同的,所以需要卸载Building类定义好的后面
{
	building = new Building3();
}

void GoodGay2::visit()
{
	cout << "visit函数正在访问: " << building->settingRoom << endl;
	cout << "visit函数正在访问: " << building->BedRoom << endl;
}

void GoodGay2::visit2()
{
	cout << "visit2函数正在访问: " << building->settingRoom << endl;
}

int main()
{
	GoodGay2 gg;
	gg.visit();
	gg.visit2();
	system("pause");
	return 0;
}

注意:这里必须使用类内声明类外定义的方法定义visit函数

  1. 我们需要在Building3类中声明GoodGay2类中的成员函数visit是友元,所以需要首先在GoodGay2类中声明或者定义函数visit。
  2. 这不是将整个GoodGay2类声明为友元,也就是说代码要在GoodGay2类中寻找这个函数visit,因此我们需要将GoodGay2类定义在Building3之前
  3. 因为我们的visit函数要访问Building3中的成员且类必须首先被定义,然后才能用引用或者指针访问其成员。因此需要将Building3类定义在visit函数之前,所以只能使用类内声明类外定义的方法,将visit函数首先在GoodGay2类中声明,然后定义Building3类,再使用类外定义的方法定义visit函数。


类的声明相关资料:
  • 不完全类型(只声明的类)只能在非常有限的情况下使用:可以定义指向这种类型的指针或引用,也可以作为一个已经声明(但没有定义)的函数的参数或返回类型。
  • 对于一个类来说,在创建它的对象前必须首先完成类的定义,而不能仅仅被声明。否则编译器就无法了解这样的对象需要多少存储空间。类似的,类也必须首先被定义,然后才能用引用或者指针访问其成员。

简而言之

  • 如果在一段代码中使用了A类实例化对象(为堆区开辟对象)或者成员变量、成员函数,那么A类必须在这段代码之前定义;
  • 如果这段代码只使用A类来定义指针或者函数参数中的数据类型那么A类可以在这段代码上面声明,而在下面定义。

参考资料: C++中的类——类的定义和声明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值