前言

简单记录一下C++中的友元,记录于此主要是方便自己查阅和回顾。

正文

定义

友元(使用关键字Friend修饰) 是一个非常强大的特性,它让类的成员函数或全局函数能够访问其他类的私有成员(private)和保护成员(protected)。

优缺点

  1. 优点:某些情况下,能够让代码更加灵活和高效。

  2. 缺点:破坏了封装。

友元函数

友元函数是在类内部声明(用friend关键字修饰)的外部函数,它可以访问该类的私有和保护成员。

友元普通函数

普通函数,然后在类中使用friend修饰和声明,这样此普通函数可以访问此类中的所有成员。

下面是计算面积的函数computerArea,如果在Rectangle类中进行使用friend修饰和声明,那么函数computerArea就可以直接访Rectangle类中的所有成员。

#include <iostream>
#include <cmath>

class Rectangle {
//一个定义为private,一个定义为protected
private:
    int height;
protected:
    int width;
public:
    Rectangle() {
        height = 0;
        width = 0;
    }

    Rectangle(int left, int top, int right, int bottom) {
        height = abs(bottom - top);
        width = abs(right - left);
    }

    int getHeight() {
        return height;
    }

    int getWidth() {
        return width;
    }

    //使用friend关键字声明为友元
    friend int computerArea(Rectangle& rectangle);
};

int computerArea(Rectangle& rectangle) {
    //普通函数只能通过public的方法获取
    //return rectangle.getHeight() * rectangle.getWidth();
    //除了方法,友元函数可以直接访问私有成员
    return rectangle.height * rectangle.width;
}

int main()
{
    Rectangle rectangle(0, 0, 100, 200);
    int area = computerArea(rectangle);
    std::cout << rectangle.getWidth() << " * " << rectangle.getHeight() << " = " << area << std::endl;
}

在类内部使用friend声明后,computerArea()可以方法类中所有的成员变量和成员函数。

友元普通函数可以看做类的一个[成员函数],但并非真正类的成员函数,但权限是一样的。

友元类函数

一个类A中使用friend修饰另外一个类B的成员函数C,那么类B的函数C可以访问类A中的所有成员。

下面例子:父亲想获取儿子的零花钱,一般情况,只能通过儿子去存钱罐中拿钱,但是如果声明未友元,父亲可以直接访问儿子的存钱罐。

#include <iostream>

class Son;//提前声明

class Father {
public:
    float getPocketMoneyFriend(Son& son);
    float getPocketMoney(Son& son);
};

class Son {
private:
    float  pocketMoney; //零花钱
public:
    Son() {
        pocketMoney = 1100;
    }
    //如果通过儿子,只能使用这个函数
    float getSonPocketMoney() {
        //超过1000时分享零花钱
        if (pocketMoney > 1000) {
            return pocketMoney - 1000;
        }
        return 0;
    }

    //但是申请友元,直接访问儿子存钱罐
    friend float Father::getPocketMoneyFriend(Son& son);
};

//友元类
float Father::getPocketMoneyFriend(Son& son) {
    //找儿子要钱
    //return son.getSonPocketMoney();
    //直接访问存钱罐
    return son.pocketMoney;
}

//非友元类
float Father::getPocketMoney(Son& son) {
    //找儿子要钱
    return son.getSonPocketMoney();
}

int main()
{
    Father father;
    Son son;
    float result = father.getPocketMoneyFriend(son);
    std::cout << result << std::endl;
    result = father.getPocketMoney(son);
    std::cout << result << std::endl;
}

从上面可以知道:

  1. 友元类函数(getPocketMoneyFriend)可以访问Son的所有成员

  2. 普通类函数(getPocketMoney)只能通过Son的public方法访问

友元类

除了友元函数,C++ 还允许整个类作为友元类。友元类可以访问另一个类的私有和保护成员。

跟友元类函数的例子差不多,还是父类找儿子要钱,这次把父亲声明未友元类。

#include <iostream>

class Son;

class Father {
public:
    float getPocketMoney1(Son& son);
    float getPocketMoney2(Son& son);
};

class Son {
private:
    float  pocketMoney; //零花钱
public:
    Son() {
        pocketMoney = 1100;
    }
    float getSonPocketMoney() {
        //超过1000时分享零花钱
        if (pocketMoney > 1000) {
            return pocketMoney - 1000;
        }
        return 0;
    }
    friend class Father;
};

float Father::getPocketMoney1(Son& son) {
    //找儿子要钱
    //return son.getSonPocketMoney();
    //直接访问存钱罐
    return son.pocketMoney;
}

float Father::getPocketMoney2(Son& son) {
    //找儿子要钱
    //return son.getSonPocketMoney();
    //直接访问存钱罐
    return son.pocketMoney;
}

int main()
{
    Father father;
    Son son;
    float result = father.getPocketMoney1(son);
    std::cout << result << std::endl;
    result = father.getPocketMoney2(son);
    std::cout << result << std::endl;
}

从上面可以知道:

  1. 声明友元类后,Father的所有函数都成为友元函数了,都可以访问Son的所有成员

注意

  1. 友元关系是不能传递的,如A是B的友元,B是C的友元,但A不是C的友元

  2. 友元关系是单向的,A是B的友元,A可以访问B的私有属性,反之不成立

  3. 友元关系是不被继承的,A是B的友元,但A的派生类不是B的友元

参考文章

  1. 《C++从入门到精通(第6版)》

  2. C++友元

  3. C++ 友元(Friend)详解

相关文章

暂无评论

none
暂无评论...