从 C 向 C++ 进阶系列导航
1. 友元简介
友元是 C++ 中的一种关系,友元关系发生在函数与类之间或者类与类之间。友元能够了忽略类的封装属性,即不受访问属性的限制,直接访问类的成员变量或成员函数。
友元具备以下特征:
- 在类中以 friend 关键字声明友元。
- 友元可以是其它类或具体函数。
- 友元不受类中访问级别的限制,可以直接访问具体类的所有成员。
- 友元不是类的一部分,仅是一种关系的声明。
- 友元关系不能被继承,是单向的,不具交换性,不具传递性。
与类有友元关系的函数称为友元函数,与类有友元关系的类称为友元类。
2. 友元类
友元类可以访问友元类声明所在的类的所有成员函数与变量。声明形式为:friend class Classname
。
- 实验:
class Test
{
private:
int mNum;
public:
Test(int num)
{
this->mNum = num;
}
void SetNum(int num)
{
this->mNum = num;
}
friend class TestFriend;
};
class TestFriend
{
public:
void PriTestNum(const Test& obj)
{
cout << "obj.mNum = " << obj.mNum << endl; // obj.mNum = 10
obj.SetNum(5);
cout << "obj.mNum = " << obj.mNum << endl; // obj.mNum = 5
obj.mNum = 10;
cout << "obj.mNum = " << obj.mNum << endl; // obj.mNum = 10
}
};
int main()
{
Test src_obj(10);
TestFriend fri_obj;
fri_obj.PriTestNum(src_obj);
}
3. 友元函数
友元函数可以访问函数声明所在的类的所有成员函数与变量。一个函数可以是多个类的友元函数,只需要在各个类中分别声明。声明形式为:friend Type Funname(...)
。
友元函数遵循以下规则:
- 当友元函数为普通函数时,函数的定义需发生在类的定义之后,或者函数的声明发生在类的声明之后。
- 当友元函数为其他类成员函数时,必须满足以下两点:
- 友元函数的所属类需定义在声明所在的类之前。
- 友元函数的形参所涉及的类需在函数所属类定义之前声明或定义。
- 两个类之间无法实现互相的友元函数。
- 实验:
class Test_B; // 必须进行声明
class Test_A; // 必须进行声明
int DifClassAdd(Test_A& obj_A, Test_B& obj_B);
class Test_B
{
private:
int mNum ;
public:
Test_B(int num)
{
this->mNum = num;
}
void SetNum(Test_A& obj_A, int num);
// friend void Test_A::PriNum(Test_B &obj_B); // invalid use of incomplete type ‘class Test_A’
friend int DifClassAdd(Test_A& obj_A, Test_B& obj_B);
};
class Test_A
{
private:
int mNum ;
public:
Test_A(int num)
{
this->mNum = num;
}
// void PriNum(Test_B& obj_B);
friend void Test_B::SetNum(Test_A& obj, int num);
friend int DifClassAdd(Test_A& obj_A, Test_B& obj_B);
};
void Test_B::SetNum(Test_A& obj_A, int num)
{
obj_A.mNum = num;
}
// void Test_A::PriNum(Test_B& obj_B)
// {
// cout << "obj_B.mNum = " << obj_B.mNum << endl;
// }
int DifClassAdd(Test_A& obj_A, Test_B& obj_B)
{
return obj_A.mNum + obj_B.mNum ;
}
int main()
{
Test_A obj_A(7);
Test_B obj_B(3);
obj_B.SetNum(obj_A, 2);
int sum = DifClassAdd(obj_A, obj_B);
cout << "obj_A.mNum + obj_B.mNum = " << sum << endl; // obj_A.mNum + obj_B.mNum = 5
}