friend友元

C++·语法 2019-03-06 4354 字 21 浏览 点赞

前言

作用:友元类的所有方法友元函数 可以访问原始类的私有成员保护成员

友元类的声明:friend class [classname];

友元函数的声明:friend [functype] [funcname] ([arglist]);

声明位置:友元声明的位置并不重要,可以public、privated和protected——没有任何区别。

什么时候考虑友元:你不是我(非同一个类),也不是我身体的一部分(不是类的成员),但你可以用我的东西(被保护【protected】起来、被保密【privated】起来的成员)。


如果一个男孩已经有女友了,同时他找了一个小三。对其他人来说,男孩的钱是私有财产,但以女友和小三的身份,总是可以轻易花掉男孩的钱。以此,完成一个简单友元类和友元函数的使用示例:

#include <iostream>

using namespace std;

/* 前置声明 */
class Girl;
void inamorata();

class Boy {
private:
    int money;

public:
    Boy(int m): money(m) {}
    void show_moeny() { cout << "boy还剩" << money << "元" << endl;}

    friend class Girl;  /* 友元类 */
    friend void inamorata(Boy& boy);  /* 友元函数 */
};

class Girl {  /* 男孩的女友 */
public:
    void go_shopping(Boy& boy) {
        boy.money--;
        cout << "girl完成购物" << endl;
    }
};

void inamorata(Boy& boy)  /* 男孩的情妇 */
{
    boy.money--;
    cout << "inamorata完成购物" << endl;
}

int main() {
    Boy boy(100);  /* 初定男孩有100块钱 */

    Girl girl;
    girl.go_shopping(boy);  /* 女孩购物 */
    boy.show_moeny();

    cout << endl << "----split line-----" << endl << endl;

    inamorata(boy);  /* 情妇购物 */
    boy.show_moeny();

    return 0;
}
// 输出:
girl完成购物
boy还剩99元

----split line-----

inamorata完成购物
boy还剩98元

(之所以把inamorata设计成函数,女孩设计成类,是因为我觉得小三见不得光,身份上应该低于正牌女友)

从输出结果可以看到,作为友元类的Girl,和友元函数的inamorata,它们可以访问原始类Boy的私有成员,也就是说,这就是友元存在的意义。

互为友元

上面的例子比较简单,正确地说,友元本身就是一个比较简单的概念。在使用友元的时候,需要着重注意的应该是:声明与定义的先后顺序。

现在假设一个场景:有一对夫妻,他们关系很好,所以可以相互使用彼此的所有东西。男人可以用女人的化妆品,女人可以穿男人的体恤衫。我们同时也假设,化妆品和体恤衫是私有的。现在利用友元类实现这个过程:

class Woman;

class Man {
private:
    string wearing = "体恤衫";
public:
    void use(Woman& woman) { cout << "男人使用了" << woman.makeup << endl;}

    friend class Woman;
};

class Woman {
private:
    string makeup = "护手霜";
public:
    void use(Man& man) { cout << "女人使用了" << man.wearing << endl;}

    friend class Man;
};

先说明:上面的代码是错误的。

如果尝试编译上述代码,会得到这样错误:error C2027: 使用了未定义类型“Woman”。上述代码里,对Woman做了前置声明,这是因为在Man类中声明了友元类(friend class Woman;),用到了Woman。然而,Man中不但用到了Woman,还用到了Woman中的私有成员:makeup。不能用makeup吗?当然可以,这是友元存在的意义。但用的不是时候,因为在Man中使用makeup时,Woman只是被声明了,还未被定义,在编译器看来,它认为Woman中并不存在makeup ,因此报错。

我们可以等Woman定义好后,再让Man的成员函数use()使用makeup,就像下边这样:

class Woman;

class Man {
private:
    string wearing = "体恤衫";
public:
    void use(Woman& woman);

    friend class Woman;
};

class Woman {
private:
    string makeup = "护手霜";
public:
    void use(Man& man) { cout << "女人使用了" << man.wearing << endl;}

    friend class Man;
};

inline  /* 在类外定义 */
void Man::use(Woman& woman) { cout << "男人使用了" << woman.makeup << endl;}

友元成员函数

使用友元类以后,就意味着友元类的所有成员函数都可以访问原始类的私有成员、保护成员。可能我们并不想这样——因为现实世界很少允许这样。比如一对夫妻,丈夫允许妻子任意花掉他的工资,但不愿意妻子使用他的手机。这个时候我们就不能鲁莽的把Woman作为Man的友元类,而应该有选择的把Woman中的成员函数设置为Man中的友元函数。

class Man;  /* 前置声明 */

class Woman{
public:
    void use_money_of_man(Man& man);
    void use_phone_of_man(Man& man);
};

class Man {
private:
    string money = "男人的钱";
    string phone = "男人的手机";

    /* 指定Woman中的use_money_of_man为Man的友元函数 */
    friend void Woman::use_money_of_man(Man& man);
};

inline  /* 不可以直接在Woman中定义 */
void Woman::use_money_of_man(Man& man)
{
    cout << "女人花掉了" << man.money << endl;
}

inline
void Woman::use_phone_of_man(Man& man)
{
    /* 此时不能使用man.phone,否则编译不通过 */
    cout << "女人不被允许使用男人的手机" << endl;
}

int main()
{
    Man man;
    Woman woman;

    woman.use_money_of_man(man);
    woman.use_phone_of_man(man);
}
// 输出:
女人花掉了男人的钱
女人不被允许使用男人的手机

也请注意此次声明与定义的先后顺序。

共同友元

现实中,也存在两个类拥有共同友元函数的情况,因为这个函数既不应该是A类的成员函数,也不应该是B类的成员函数。比方说一对夫妻生下了一个孩子,这个孩子是独立存在的,也不是男人身体的一部分,也不是女人身体的一部分,但他又可以花男人的钱,也可以花女人的钱。所以这个孩子对于男人和女人来说,就是共同的友元函数。

class Man;

class Woman{
private:
    string money = "女人的钱";

    friend void son(Man& man, Woman& woman);
};

class Man {
private:
    string money = "男人的钱";

    friend void son(Man& man, Woman& woman);
};

void son(Man& man, Woman& woman)
{
    cout << "花" << man.money << endl;
    cout << "花" << woman.money << endl;
}

int main()
{
    Man man;
    Woman woman;

    son(man, woman);
}
// 输出:
花男人的钱
花女人的钱


本文由 Guan 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论