C++之友元

C++友元提供了一种普通函数或者类成员函数,访问另一个类中的私有或者保护成员的机制。


概述

C++友元可以分类两种形式:

  • 友元函数:普通函数访问某个类中的私有或者保护成员
  • 友元类:友元类可以访问该类中所有的私有或者保护成员
    友元提高了程序的运行效率,但也破坏了类的封装和数据的透明性。

友元函数

友元函数是类外定义的、不属于当前类的函数也可以在类中声明,但要在前面加friend关键字,这样就构成了友元函数。友元函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。
友元函数可以访问当前类中的所有成员,包括public、protected、private。

非成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
class Student {
public:
Student(string name, int age, float score) : m_name(name), m_age(age), m_score(score) {}
friend void Show(const Student&);
private:
string m_name;
int m_age;
float m_score;
};
void Show(const Student& stu) {
cout << stu.m_name << ", age: " << stu.m_age << ", socre: " << stu.m_score << endl;
}
int main() {
Student stu("Harlon", 25, 88);
Show(stu);
return 0;
}

运行结果:

1
Harlon, age: 25, socre: 88

类的成员函数可以隐式的增加this指针,指明被调用的对象,从而使用该对象的成员;而普通的非成员函数作为类的友元函数时,并没有this指针,所以必须通过对象去引用类的成员。

其他类的成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;
class Address;
class Student {
public:
Student(string name, int age, float score) : m_name(name), m_age(age), m_score(score) {}
void Show(const Address&);
private:
string m_name;
int m_age;
float m_score;
};
class Address {
public:
Address(string province, string city, string district) :
m_province(province), m_city(city), m_distict(district) {}
friend void Student::Show(const Address &);
private:
string m_province;
string m_city;
string m_distict;
};
void Student::Show(const Address& info) {
cout << m_name << ", age: " << m_age << ", socre: " << m_score << endl;
cout << "province: " << info.m_province << ", city: " << info.m_city << ", district: " << info.m_distict << endl;
}
int main() {
Student stu("Harlon", 25, 88);
Address ad("Hubei", "wuhan", "hongshan");
stu.Show(ad);
return 0;
}

运行结果:

1
2
Harlon, age: 25, socre: 88
province: Hubei, city: wuhan, district: hongshan


友元类

在C++中,也可以将一个类声明为另一个类的友元,友元类的所有成员函数都是这个类的友元函数。
例如将B声明为A的友元类,那么类B中的所有盛有函数都是类A的友元函数,可以访问类A的所有成员,包括public,private,private属性的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;
class Address;
class Student {
public:
Student(string name, int age, float score) : m_name(name), m_age(age), m_score(score) {}
void Show(const Address&);
private:
string m_name;
int m_age;
float m_score;
};
class Address {
public:
Address(string province, string city, string district) :
m_province(province), m_city(city), m_distict(district) {}
friend class Student;
private:
string m_province;
string m_city;
string m_distict;
};
void Student::Show(const Address& info) {
cout << m_name << ", age: " << m_age << ", socre: " << m_score << endl;
cout << "province: " << info.m_province << ", city: " << info.m_city << ", district: " << info.m_distict << endl;
}
int main() {
Student stu("Harlon", 25, 88);
Address ad("Hubei", "wuhan", "hongshan");
stu.Show(ad);
return 0;
}

对于友元函数,有以下三点要注意:

  • 友元关系不是双向的,如果声明了类B是类A的友元类,不等于类A是类B的友元类,类A中的成员函数不能访问类B中的private成员。
  • 友元关系不能传递,如果类B是类A的友元类,类C是类B的友元类,不等于类C是类A的友元类。
  • 友元关系不能继承,如果类B是类A的友元类,类C继承了类B,类B不是类C的友元类,类B并不能访问类C中的private成员。

参考资料
【C++基础之十】友元函数和友元类
C++ friend友元函数和友元类