目录

一、友元函数

二、友元类

三、友元的优缺点


一、友元函数

结合着类的特性,可知:类具有封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性。另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。

为了解决上述问题,提出一种使用友元的方案。友元是一种定义在类外部的普通函数,但它需要在类体内进行声明,为了与该类的成员函数加以区别,在声明时前面加以关键字friend友元不是成员函数,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。

案例分析:

问题:现在我们尝试去重载operator<<,然后发现我们没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以我们要将operator<<重载成全局函数。但是这样的话,又会导致类外没办法访问成员,那么这里就需要友元来解决。operator>>同理。

#include <iostream>
using namespace std;

class Date
{
    friend ostream& operator<<(ostream& _cout, const Date& d);
    friend istream& operator>>(istream& _cin, Date& d);
public:
    Date(){}
    Date(int year, int month, int day): _year(year), _month(month), _day(day)
    {}

private:
    int _year;
    int _month;
    int _day;
};

ostream& operator<<(ostream& _cout, const Date& d)
{
    _cout<<d._year<<"-"<<d._month<<"-"<<d._day;
    return _cout;
}

istream& operator>>(istream& _cin,Date& d)
{
    _cin>>d._year;
    _cin>>d._month;
    _cin>>d._day;
    return _cin;
}

int main()
{
    Date d;
    cin>>d;
    cout<<d<<endl;
    return 0;
}

 【说明】

  • 友元函数可访问类的私有成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用和原理相同

二、友元类

友元除了友元函数以外,友元还可以是类——友元类,即一个类可以作另一个类的友元。当一个类作为另一个类的友元时,这就意味着这个类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的非公有成员。

特性:

  • 友元关系是单向的,不具有交换性。

比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。

  • 友元关系不能传递

如果B是A的友元,C是B的友元,则不能说明C时A的友元。

  • 友元关系不能被继承,但对已有的方法来说访问权限不改变。

class Date; // 前置声明
class Time
{
    friend class Date; 
    // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public:
    Time(int hour, int minute, int second): _hour(hour), _minute(minute), _second(second)
    {}

private:
    int _hour;
    int _minute;
    int _second;
};

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1): _year(year),                                     
    _month(month),_day(day)
    {}
    void SetTimeOfDate(int hour, int minute, int second)
    {
        // 直接访问时间类私有的成员变量
        _t._hour = hour;
        _t._minute = minute;
        _t.second = second;
    }
private:
    int _year;
    int _month;
    int _day;
    Time _t;
};

三、友元的优缺点

利用 friend 修饰符,可以让一些普通函数 或 另一个类的成员函数 直接对某个类的保护成员和私有成员进行操作,提高了程序的运行效率;同时避免把类的成员都声明为public,最大限度地保护数据成员的安全。

但是,即使是最大限度地保护数据成员,友元也破坏了类的封装性。

如果将类的封装比喻成一堵墙的话,那么友元机制就像墙上开了一个门。所以使用友元时一定要慎重。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐