友元函数
前面讲过,类的数据成员有三种访问权限:public、private、protected。成员函数可以访问所有的数据成员,而不属于这个类的函数,我们叫做非成员函数,只能访问public的数据成员。就有这么一种情况发生了,一个数据成员允许某个非成员函数而不是所有的非成员函数访问,那怎么办?显然将这个数据成员定义成public的所有非成员函数都能访问到,这不合适,定义成private、protected,所有的非成员函数都访问不到,这也不合适。所以就要用到友元的概念了。
友元机制允许一个类授权非成员函数访问它的非public数据成员。友元可以是函数,叫做友元函数,友元可以是类叫做友元类。先说友元函数,注意以下几点:
1.友元函数以关键字friend开头。
2.友元函数声明在类体中,定义在类体外。
3.友元函数不是类的成员函数,它是特殊的非成员函数,所以友元函数在访问类的成员时必须使用对象名。
4.友元函数与普通的非成员函数区别是,声明在类体内,并可以访问类对象的私有成员。
5.友元函数也可以是另一个类的成员函数。这是肯定的,对类A来说,所有的函数分为两类,类A的成员函数,类A的非成员函数。类B的成员函数,也是类A的非成员函数,所有也可以定义为A的友元函数。
6.友元函数破坏了函数的封装性,和信息的隐蔽性,慎用吧~
#include <iostream>
using namespace std;
class Point;
class Persion{
public:
Persion(int a){pid=a;}
void pMovepoint(Point &,int a,int b);
private:
int pid;
};
class Point
{
public:
Point(int a,int b=3){x=a;y=b;}//声明并实现构造函数
void setXY(int a,int b){x=a;y=b;}
void move(int a,int b){x+=a;y+=b;}
void printPoint(){cout<<"x= "<<x<<" y= "<<y<<endl;}
//友元函数为其他类的成员函数
friend void Persion::pMovepoint(Point &,int a,int b);
friend void movePoint(Point &,int a,int b);
private:
int x,y;
};
//友元函数实现
void Persion::pMovepoint(Point &p,int a,int b)
{
p.x+=a;
p.y+=b;
}
//友元函数实现
void movePoint(Point &p,int a,int b)
{
p.x+=a;
p.y+=b;
}
void main()
{
Point p1(1,2);
p1.printPoint();
movePoint(p1,2,2);
p1.printPoint();
Persion persion(1);
persion.pMovepoint(p1,1,1);
p1.printPoint();
}
第38、40、43行调用printPoint输出为:
x= 1 y= 2
x= 3 y= 4
x= 4 y= 5
第3行写class Point;是为什么?因为Point类的定义在后面,Persion类的定义在前面,如果不提前说一下Point是一个类,那么程序编译到第7行的时候,就不知道Point是什么,就会报错。第3行的目的就是告诉编译器Point是一个类,具体的定义在后面。这样编译器编译到第7行就不会报错了。
第7行声明成员函数pMovepoint,它类Persion的普通成员函数。但在第18行,这个函数被声明为类Point的友元函数。
第19行被声明函数movePoint为类Point的友元函数。注意函数pMovepoint和movePoint,一个是类的成员函数,一个是普通函数,两者都可以作为类Point的友元函数。注意两者声明和定义时写法上的区别。
第39行,通过调用movePoint函数,把p1的私有变量的值改变了。第42行,通过调用Persion类的pMovepoint函数,把p1的私有变量的值也改变了。这就是友元函数的意义。
友元类
友元也可以是类,叫做友元类。若类B是类A的友元类,那么类B的所有成员函数都是类A的友元函数,都可以访问类A的私有成员。
注意友元类不具有传递性:若类B是类A的友元类,类C是类B的友元类,这不表示类C也是类A的友元类。
友元类不具有交换性:若类B是类A的友元类,不表示类A也是类B的友元类
概念清晰了,就看怎么写代码,简单举例:
#include <iostream>
using namespace std;
class Point
{
friend class Persion;
public:
Point(int a,int b=3){x=a;y=b;}//声明并实现构造函数
void setXY(int a,int b){x=a;y=b;}
void move(int a,int b){x+=a;y+=b;}
void printPoint(){cout<<"x= "<<x<<" y= "<<y<<endl;}
private:
int x,y;
};
class Persion{
public:
Persion(int a){pid=a;}
void pMovepoint(Point &,int a,int b);
private:
int pid;
};
void Persion::pMovepoint(Point &p,int a,int b)
{
p.x+=a;
p.y+=b;
}
第5行,说明类Persion是类Point的友元类。所以类Persion的成员函数pMovepoint在定义时,就可以访问类Point的私有数据成员。