C++编程入门(二) 互动版

在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器

友元函数

前面讲过,类的数据成员有三种访问权限: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的私有数据成员。