先上一段代码。定义了两个类,都有私有变量num。分别用全局函数、友元函数计算两者的和。

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
39
40
41
#include<iostream>
using namespace std;

class B;
class A; // 此行可不加,这里加此行是因为下面举例子有用
class A {
public:
A(int n = 0): num(n) {} // 构造函数
friend void sum_1(A &a, B &b); // 全局函数 sum_1
void sum_2(B &b); // 成员函数 sum_2
private:
int num;
};

class B {
public:
B(int n = 0) : num(n) {} // 构造函数
friend void sum_1(A &a, B &b); // 全局函数 sum_1
friend void A::sum_2(B &b); // 友元函数 A::sum_2
private:
int num;
};
// 全局函数
void sum_1(A &a, B &b) {
int sum = a.num + b.num; // 访问了两个对象的私有变量
cout << a.num << " + " << b.num << " = " << sum << endl;
}
// 友元函数
void A::sum_2(B &b) {
int sum = num + b.num; // 访问了参数对象的私有变量
cout << num << " + " << b.num << " = " << sum << endl;
}

int main() {
A a(1);
B b;
sum_1(a, b); // 调用全局函数
a.sum_2(b); // 调用a的成员函数
system("PAUSE");
return 0;
}

1. 提前声明要使用的类
1
class B;

编译器会报错:error C2061: 语法错误: 标识符“B”

本例中,先对类 B 进行了声明,但是没有定义。因为在类 A 的定义中,出现的函数 sum_1sum_2 均要用到类B 名,所以必须事先声明“B”是一个类名,这样编译器才不会因为不知道”B“是什么而报错。

2. 必须将先定义的类的成员函数作为后定义类的友元函数,调换顺序会出现语法错误

本例中,若将 A、B 类的定义顺序调换,其余均不变,则出现语法错误

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>  
using namespace std;

class B;
class A; // 此行可不加,这里加此行是因为下面举例子有用
class B { // A、B类的定义顺序变了
.../*中间的语句不变*/
};
class A {
.../*中间的语句不变*/
};
.../*后面的语句不变*/

在友元函数的实现中,会出现

img

这说明B类中没有成功的把A类的成员函数sum_2声明为自己的友元函数。 道理很很简单,和第1点很相似。若先定义B类,那么我们观察一下B类定义中的如下语句

1
friend void A::sum_2(B &b);     // 友元函数 A::sum_2

该语句通过类名加域运算符,将A类的成员函数sum_2声明为友元函数。等等,是不是发现了什么,这是A类根本还没有定义,编译器只知道A是一个类名,A中具体有什么全然不知。如此,那么这一个语句当然无效咯!


likeqc
ends