友元(友元函数、友元类、类成员函数的友元)
(friend)友元机制:允许一个类将对其非公有成员的访问权限授予指定的函数或者类。
我们可以将友元大致分为3类:
- 友元函数
- 友元类
- 类成员函数的友元
一:友元函数
友元函数:是指某些虽然不是类的成员函数,但是能够访问这个类的所有成员的函数。
比如我们下列的代码:
#include <iostream>
class Test
{
public:
Test(int a, int b):ma(a), mb(b){}
friend void show(Test &rhs);//声明 你show这个函数 是 我Test类的朋友了
private: //你可以访问我的所有成员
int ma;
int mb;
};
void show(Test &rhs)
{
rhs.ma++; //为了验证是否可以访问Test类的私有成员,我们对其进行修改并打印
std::cout << "ma:" << rhs.ma << std::endl;
std::cout << "mb:" << rhs.mb << std::endl;
}
int main()
{
Test test1(10, 20);
show(test1);
return 0;
}
我们可以运行一下结果,看是否和我们预想的一致:
我们通过测试结果可以得出结论:函数show确实访问到了Test类的私有成员。
二:友元类
友元类:相当于友元函数的扩张版本,指你友元类的所有成员函数 都是 我这个类的友元函数,你所有的成员函数都可以访问我这个类的所有成员,我对你没有秘密。
应用:当希望一个类可以访问另一个类的私有成员时,可以将该类声明为另一个类的友元类。
关于友元类的特点:
- 友元关系不能被继承
- 友元关系是单向的,不具备交换性,例如我声明你是我的朋友,那你可以从我口袋拿钱,但是不代表我就变成了你的朋友,我是不能从你口袋拿钱的。
- 友元关系不具有传递性,例如B是A的朋友,C是B的朋友,但是不代表C就变成A的朋友了。
比如我们下列的代码:
#include <iostream>
class Link;
class Node
{
public:
Node(int val = 0) :mdata(val), pnext(NULL){}
private:
int mdata;
Node* pnext;
friend class Link;//声明类Link是类Node的朋友
//指类Link中的所有成员函数都可以访问类Node中的所有成员
};
class Link //友元类定义,为了可以访问到类Node中的成员
{
public:
Link() :phead(new Node()){}
~Link()
{
Node* pCur = phead;
Node* pNext = pCur;
while (pCur != NULL)
{
pNext = pCur->pnext;
delete pCur;
pCur = pNext;
}
}
void insert(int val)
{
Node* pnewnode = new Node(val);
pnewnode->pnext = phead->pnext;
phead->pnext = pnewnode;
}
void Show()
{
Node* pCur = phead->pnext;
while (pCur != NULL)
{
std::cout << pCur->mdata << " ";
pCur = pCur->pnext;
}
std::cout << std::endl;
}
private:
Node* phead;
};
int main()
{
Link link1;
for (int i = 0; i < 10; i++)
{
link1.insert(i + 1);
}
link1.Show();
return 0;
}
我们可以运行一下结果,看是否可以对类Node进行访问:
我们通过测试结果可以得出结论:类Link确实访问到了类Node中的私有成员。
三:类成员函数的友元
类成员函数的友元:相当于友元类的缩小版本,指一个类中被声明的特定成员函数 可以 访问到另一个类中的所有成员。
注意:当用到类成员函数的友元时,需要注意友元声明与友元定义之间的相互依赖,比如下面这个例子,类B必须先定义好,才能定义类A的该友元成员函数。
比如我们下列的代码:
#include <iostream>
class B; //当用到友元成员函数时,需要注意友元声明与友元定义之间的相互依赖。这时类B的声明
class A
{
public:
void show(B &rhs);//声明该函数是类B的友元函数,这里不能直接写函数体,因为这时还不能访问类B的私有成员
};
class B
{
public:
B(int a, int b):ma(a), mb(b){}
friend void A::show(B &rhs); //这里声明该函数A::show是类B的友元成员函数
private:
int ma;
int mb;
};
void A::show(B &rhs) //这里才是友元成员函数的定义
{ //只有在定义B之后,才知道该函数是类B的友元,这时才能成功访问类B的所有成员
//所以这时才定义该函数,毕竟,它被设为友元是为了访问类B的成员
rhs.ma++;
std::cout << "ma:" << rhs.ma << std::endl;
std::cout << "mb:" << rhs.mb << std::endl;
}
int main()
{
A a1;
B b1(10, 20);
a1.show(b1);
return 0;
}
我们可以运行一下结果,看是否函数A::show可以对类B进行访问:
我们通过测试结果可以得出结论:类A中的函数show确实访问到了类B中的私有成员。
四:对于友元的建议
- 我们都知道C++的三大特点:封装、继承、多态,封装通过权限控制保证了类的安全性
- 而友元打破了这种封装性,会使其变得不安全
- 所以我们建议能不用友元,就尽量不要用友元,不得不用的时候再用友元。
至此,友元的基础概念复习完毕。