C++之友元

一、友元的目的
先来扯一些为什么要用友元这么个东东。首先,类中不管是数据成员还是成员函数,都有各自不同的访问权限,有的是public,有的是private,还有的是protected。对于类的封装特性,一般都会把数据成员的访问权限设置为private,那么外部函数或者其他类想访问该类的数据成员怎么办?
第一种方法:

class A{
private:
    int x;
    int y;
    int z;
public:
    void getX(){
        return x;
    }
    void getY(){
        return y;
    }
    void getZ(){
        return z;
    }
};

void print(A& a){
    cout << a.getX() << a.getY() << a.getZ << endl;
}

可以向上面代码一样,在A类里定义公共的接口,那么print调用三个接口就可以获得A的私有数据成员x, y, z。这么做并没有什么问题对吧,但是如果print()执行一万次、一千万次呢,就需要每次都调用三个接口,这样效率是非常慢的。那么就要用到友元了。

二、友元函数
先把上面的代码改成友元,看一下效果:

class A{
private:
    int x;
    int y;
    int z;
public:
    friend void print(A &a);
};

void print(A& a){
    cout << a.x << a.y << a.z << endl;
}

是不是看起来简单多了,声明print函数为类A的友元,便可以随意的访问类A的私有成员。从这便可以看出友元的特点:
1)破坏了类的封装性;
2)提高了效率。

前面说的是友元函数是一个全局函数,用样也可以是类中的成员函数:

class A;
class B{
    public:
    void print(A &a)
};
class A{
private:
    int x;
    int y;
    int z;
public:
    friend void B::print(A &a);
};

void B::print(A& a){
    cout << a.x << a.y << a.z << endl;
}

这个结构就有点复杂了,首先类B的成员函数print要被声明为类A的友元,不能这样写:

class A{
private:
    int x;
    int y;
    int z;
public:
    friend void B::print(A &a);
};
class B{
public:
    void print(A& a){
        cout << a.x << a.y << a.z << endl;
    }
}

类A中有

friend void B::print(A &a);

这么一个玩意,那类B从哪来的呢,或许会说把类B放到前面进行声明,那这个地方就要注意一下,这里对前向声明做个小小的解释:
前向声明是一种不完全类型的声明,只提供类名,不提供实现。那么就有一定的局限性:
1.不能定义类的对象;
2.可以定义指向这个类型的指针或引用;
3.使用这个类型当做函数形参类型或者函数返回值类型。
声明针对指针或者引用,因为指针引用的大小系统是能够确定的,如果把类B放在前面声明,但是系统仍然不知道类B占用的空间是多少,应该开辟多少空间给他,而且前向声明没有实现,不知道B中有print函数,so类B放在前面声明仍然报错,那就说了,直接把类B全部内容放到类A的前面:

class B{
public:
    void print(A& a){
        cout << a.x << a.y << a.z << endl;
    }
}
class A{
private:
    int x;
    int y;
    int z;
public:
    friend void B::print(A &a);
};

问题又来了,类B的成员函数print有这么个玩意:

void print(A& a)

那A又从哪来的,这里类A是个引用,故可以在类B前面声明类A,还有问题,print里面还有:

cout << a.x << a.y << a.z << endl;

这么个玩意,x, y, z从哪里的呢,在类A的前向声明并不告知x, y, z这些东西,并不知道类A中有什么,那么该怎么办呢?这时候就把print函数放到类B外面,类A的下面定义, 最终就是这样的:

class A;
class B{
public:
    void print(A &a);
};
class A{
private:
    int x;
    int y;
    int z;
public:
    friend void B::print(A &a);
};

void B::print(A& a){
    cout << a.x << a.y << a.z << endl;
}

三、友元类
上面说的都是友元函数,当一个类B专门用来操纵另一个类A时,如果类B中的所有成员函数都定义为类A的友元是非常麻烦的,这时候友元类就非常方便了,直接把类B定义为类A的友元类,同样举个例子:

class NUM{
private:
    int x;
    int y;
public:
    NUM(int x, int y): x(x), y(y){}
    friend class OPT;
};

class OPT{
public:
    void add(NUM &n){
        cout << n.x + n.y << endl;
    }
    void reduce(NUM &n){
        cout << n.x - n.y << endl;
    }
    void multiply(NUM &n){
        cout << n.x * n.y << endl;
    }
    void divide(NUM &n){
        cout << n.x / n.y << endl;
    }
}

友元类相比友元的类成员函数要简单很多,不用提前声明。
友元类终归一句话:
声明为谁的友元,就可以通过谁的对象,访问谁的私有成员。(好好体会这句话)

这里说一点,友元的声明位置不重要,可以在类的private下,也可以在public,也可以在protected,不影响,但一般建议放在public下,因为是拿来公用的嘛。

注意事项:
这里说一下友元的关系:
1.友元不能被继承,也就是说父类B是类A的友元类,那类B的子类C不一定是类A的友元类
2.友元不具有传递性,类B是类A的友元类,类A的是类C的友元类,但类B不一定是类C的友元类
2.友元不具有双向性,类B是类A的友元类,类A不一定是类B的友元类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值