24.友元函数
1.友元
类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部(作用域之外)访问。但是,有时候需要在类的外部访问类的私有成员,怎么办?
解决方法是使用友元函数,友元函数是一种特权函数,c++允许这个特权函数访问私有成员。这一点从现实生活中也可以很好的理解:
比如你的家,有客厅,有你的卧室,那么你的客厅是Public的,所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去,但是呢,你也可以允许你的闺蜜好基友进去。
程序员可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元。
1.1.友元语法
● friend关键字只出现在声明处
●其他类、类成员函数、全局函数都可声明为友元
●友元函数不是类的成员,不带this指针
●友元函数可访问对象任意成员属性,包括私有属性
class Building;
//友元类
class MyFriend{
public:
//友元成员函数
void LookAtBedRoom(Building& building);
void PlayInBedRoom(Building& building);
};
class Building{
//全局函数做友元函数
friend void CleanBedRoom(Building& building);
#if 0
//成员函数做友元函数
friend void MyFriend::LookAtBedRoom(Building& building);
friend void MyFriend::PlayInBedRoom(Building& building);
#else
//友元类
friend class MyFriend;
#endif
public:
Building();
public:
string mSittingRoom;
private:
string mBedroom;
};
void MyFriend::LookAtBedRoom(Building& building){
cout << "我的朋友参观" << building.mBedroom << endl;
}
void MyFriend::PlayInBedRoom(Building& building){
cout << "我的朋友玩耍在" << building.mBedroom << endl;
}
//友元全局函数
void CleanBedRoom(Building& building){
cout << "友元全局函数访问" << building.mBedroom << endl;
}
Building::Building(){
this->mSittingRoom = "客厅";
this->mBedroom = "卧室";
}
int main(){
Building building;
MyFriend myfriend;
CleanBedRoom(building);
myfriend.LookAtBedRoom(building);
myfriend.PlayInBedRoom(building);
system("pause");
return EXIT_SUCCESS;
}
[友元类注意]
1.友元关系不能被继承。
2.友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友。
3.友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友。
思考: c++是纯面向对象的吗?
如果一个类被声明为friend,意味着它不是这个类的成员函数,却可以修改这个类的私有成员,而且必须列在类的定义中,因此他是一个特权函数。c++不是完全的面向对象语言,而只是一个混合产品。增加friend关键字只是用来解决一些实际问题,这也说明这种语言是不纯的。毕竟c++设计的目的是为了实用性,而不是追求理想的抽象。
--- Thinking in C++
2.视频内容
程序1(全局函数的友元):
#pragma warning(disable:4996)
//2022年9月26日20:02:07
#include <iostream>
using namespace std;
#include <string>
class Building
{
//声明这个全局函数为Building类的友元函数
friend void GoodGay(Building &bd);
private:
string woshi;
public:
string keting;
public:
Building()
{
keting = "客厅";
woshi = "卧室";
}
};
void GoodGay(Building& bd)
{
cout << "好基友访问:" << bd.keting << endl;
cout << "好基友访问:" << bd.woshi << endl;
}
void test01()
{
Building my;
GoodGay(my);
}
int main()
{
test01();
system("pause");
return EXIT_SUCCESS;
}
输出结果:
好基友访问:客厅
好基友访问:卧室
请按任意键继续. . .
重点难点:
1 友元的作用:在类外访问类的私有成员
2 友元分:友元函数,友元类,成员函数的友元函数
3 在普通函数或类的前面加上friend,在类中声明
4 友元类不能被继续,友元是单向,友元没有传递性
程序2(友元类):
#pragma warning(disable:4996)
//2022年9月26日21:00:093
#include <iostream>
using namespace std;
class Building
{
//声明GoodF类为友元类
friend class GoodF;
public:
string keting;
private:
string woshi;
public:
Building()
{
keting = "客厅";
woshi = "卧室";
}
};
class GoodF
{
public:
void func(Building &bd)
{
cout << "访问: " << bd.keting << endl;
cout << "访问: " << bd.woshi << endl;
}
};
//1.通过传入参数来访问类的私有成员
void test01()
{
Building bd;
GoodF f;
f.func(bd);
}
int main()
{
test01();
system("pause");
return EXIT_SUCCESS;
}
输出结果:
访问: 客厅
访问: 卧室
请按任意键继续. . .
程序3:
#pragma warning(disable:4996)
//2022年9月26日21:00:093
#include <iostream>
using namespace std;
class Building
{
//声明GoodF类Building类的友元类
friend class GoodF;
friend class GoodF2;
public:
string keting;
private:
string woshi;
public:
Building()
{
keting = "客厅";
woshi = "卧室";
}
};
class GoodF
{
public:
void func(Building &bd)
{
cout << "访问: " << bd.keting << endl;
cout << "访问: " << bd.woshi << endl;
}
};
//1.通过传入参数来访问类的私有成员
void test01()
{
Building bd;
GoodF f;
f.func(bd);
}
//2.通过类内指针来访问类的私有成员
class GoodF2
{
public:
Building *pbu;
public:
GoodF2()
{
pbu = new Building;
}
void func()
{
cout << "访问: " << pbu->keting << endl;
cout << "访问: " << pbu->woshi << endl;
}
};
void test02()
{
GoodF2 f;
f.func();
}
int main()
{
test02();
system("pause");
return EXIT_SUCCESS;
}
输出结果:
访问: 客厅
访问: 卧室
请按任意键继续. . .
程序4:
#pragma warning(disable:4996)
//2022年9月26日21:00:093
#include <iostream>
using namespace std;
class Building
{
//声明GoodF类Building类的友元类
friend class GoodF;
friend class GoodF2;
public:
string keting;
private:
string woshi;
public:
Building()
{
keting = "客厅";
woshi = "卧室";
}
};
class GoodF
{
public:
void func(Building& bd)
{
cout << "访问: " << bd.keting << endl;
cout << "访问: " << bd.woshi << endl;
}
};
//1.通过传入参数来访问类的私有成员
void test01()
{
Building bd;
GoodF f;
f.func(bd);
}
//2.通过类内指针来访问类的私有成员
class GoodF2
{
public:
Building* pbu;
public:
GoodF2()
{
cout << "无参构造" << endl;
pbu = new Building;
}
void func()
{
cout << "访问: " << pbu->keting << endl;
cout << "访问: " << pbu->woshi << endl;
}
//拷贝构造
GoodF2(const GoodF2& f2)
{
cout << "拷贝构造" << endl;
//1.申请空间
pbu = new Building;
////2.拷贝数据
//pbu->keting =
}
~GoodF2()
{
cout << "析构函数" << endl;
if (pbu != NULL)
{
delete pbu;
}
}
};
void test02()
{
GoodF2 f;
f.func();
GoodF2 f2 = f;
}
int main()
{
test02();
system("pause");
return EXIT_SUCCESS;
}
输出结果:
访问: 客厅
访问: 卧室
拷贝构造
析构函数
析构函数
请按任意键继续. . .
程序5:
#pragma warning(disable:4996)
//2022年9月30日18:37:34
#include <iostream>
using namespace std;
//1.编译器直到类的声明,不知道类的结构
class Building;//声明类
class GoodGay
{
public:
void func(Building& bud);
};
class Building
{
//声明GoodGay类的成员func()成为BUilding类的友元函数
friend void GoodGay::func(Building &bud);
public:
Building()
{
keting = "客厅";
woshi = "卧室";
}
public:
string keting;
private:
string woshi;
};
void GoodGay::func(Building& bud)
{
cout << "访问:" << bud.keting << endl;
cout << "访问:" << bud.woshi << endl;
}
void test()
{
Building bud;
GoodGay GF;
GF.func(bud);
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
输出结果:
访问:客厅
访问:卧室
请按任意键继续. . .