《新编C++语言习题与解析》试读:4.1 基本知识点
第4章 友 元
本章学习要点
深入掌握友元函数的相关概念和使用方法。
深入掌握友元类的相关概念和使用方法。
灵活运用友元的相关知识进行综合程序设计。
4.1 基本知识点
4.1.1 友元函数
友元函数是一种特殊的函数,它需要在类体内进行说明,可以访问类的私有成员,但又不是类的成员函数。友元函数的说明格式如下:
friend 数据类型 函数名(参数表)
其中,friend是说明友元函数的关键字。
归纳起来,友元函数是一种能够访问类中的私有成员的非成员函数。友元函数在定义上和调用上与普通函数一样。
友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。因此,只有在十分需要时才使用友元函数。
例如,分析下列程序的输出结果。
#include <iostream.h>
#include <math.h>
class TPoint
{ double x,y; //私有数据成员
public:
TPoint(double a,double b) //构造函数
{ x=a,y=b; cout << "点:(" << x << "," << y << ")" << endl; }
friend double distance(TPoint &a,TPoint &b) //友元函数
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
};
void main()
{ TPoint p1(2,2),p2(5,5);
cout << "上述两点之间的距离:" //调用友元函数
<< distance(p1,p2) << endl;
}
在上述程序中,distance()是类TPoint的友元函数,在其中可以直接使用a.x等,由于x等是类TPoint的私有成员,所以在普通函数中是不能这样使用的。调用友元函数distance(p1,p2)时也不需要加上对象前缀。该程序执行结果如下:
点:(2,2)
点:(5,5)
上述两点之间的距离:4.24264
友元函数的一个重要特征是它可以是多个类的友元。
例如,编写一个程序,求一个点到直线的距离。
设计一个点类Point,它有两个私有数据成员x和y,表示点的坐标。另一个类为直线类Line,它有三个私有数据成员a、b和c,表示直线方程ax+by+c=0。这两个类中都说明了一个友元函数dist,用于计算一个点到直线的距离。点(x,y)到直线ax+by+c=0的距离d的计算公式如下:
求解程序如下:
#include <iostream.h>
#include <math.h>
class Line; //提前说明
class Point
{ int x,y;
public:
Point(int x1,int y1)
{ x=x1; y=y1; }
friend double dist(Line l,Point p); //友元函数声明
};
class Line
{ int a,b,c;
public:
Line(int a1,int b1,int c1)
{ a=a1; b=b1; c=c1; }
friend double dist(Line l,Point p); //友元函数声明
};
double dist(Line l,Point p) //计算点对象p到直线对象l之间的距离
{ double d;
d=abs(l.a*p.x+l.b*p.y+l.c)/(sqrt(l.a*l.a+l.b*l.b));
return d;
}
void main()
{ Point p(10,10);
Line l(2,4,-3);
cout << "d=" << dist(l,p) << endl;
}
上述程序中有两个类Point和Line,它们都说明了同一友元函数:friend double dist(Line l,Point p)。由于在Point类中说明时尚未定义Line类,所以需要在前面用class Line;语句进行提前说明。该程序的执行结果如下:
d=12.7456
一个类A的成员函数f()可以作为另一个类B的友元函数,在这种情况下,必须先定义A类,并且在B类中说明友元函数f()时,要加上成员函数所在类的类名,即:
class A
{ …
数据类型 f(参数表);
…
}
class B
{ …
friend 数据类型 A::f(参数表);
…
}
数据类型 A::f(参数表)
{
函数体;
}
4.1.2 友元类
除了前面讲过的友元函数外,友元还可以是一个类,即一个类可以作为另一个类的友元。当一个类作为另一个类的友元时,就意味着这个类的所有成员函数都是另一个类的友元函数。例如,以下程序说明类B是类A的友元类:
class A
{ ...
public:
friend class B; //说明B是A的友元类
...
}
例如,有以下程序:
#include <iostream.h>
#include <math.h>
class A
{ int x;
public:
A() {x=5;}
friend class B;
};
class B
{
public:
void disp1(A tmp) {tmp.x++;cout << "disp1: x=" << tmp.x << endl; }
void disp2(A tmp) {tmp.x--;cout << "disp2: x=" << tmp.x << endl; }
};
void main()
{ A obj1;
B obj2;
obj2.disp1(obj1);
obj2.disp2(obj1);
}
上述程序中,类B是类A的友元类,类B包括两个成员函数,这两个成员函数可以当成类A自已的友元函数一样使用。该程序的执行结果如下:
disp1:x=6
disp2:x=4
使用友元类时注意以下几点:
友元关系不能被继承。
友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的声明。