类和对象之友元

在这里插入图片描述

友元

友元是一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员,不可以使用对象名去调用它。

友元函数

友元函数是在类定义中由关键字friend修饰的非成员函数。其格式如下:

friend 返回类型 函数名(形参表)
{
	//函数体
}

示例

class Person
{
	friend istream& operator>>(istream& in, Person& p);  //全局函数做友元
private:

	int m_A;
	int m_B;
};
istream& operator>>(istream &in,Person &p)
{
	in>>p.m_A>>p.m_B;
	return in;
}

友元类

如果一个类声明为另一个类的友元,则该类称为另一个类的友元类。若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都是可以访问B类的任何数据成员。
友元类的声明是在类名之前加上关键字friend实现的。声明A类为B类的友元类的格式如下:

class B
{
	friend class A;
};

这里要注意一个问题,就是当声明A类为B类的友元类时,A类必须已经存在,但是如果A类又将B类声明为自己的友元类,又会出现B类不存在的错误。这种情况,C++专门规定了前向引用声明,用与解决这类问题。
例如下述情况:

class B;            //前向引用声明
class A             //A类的定义
{
public:
    void funA(B b); //以B类对象b为形参的成员函数
};

class B             //B类的定义
{
public:
    void funB(A a); //以A类对象a为形参的成员函数
};

示例

下面我们就写一个计算某次火车的旅途时间的友元类为例,加深对友元的掌握。

#include<iostream>

class TrainTrip;        //前向引用声明
class Clock
{
    friend class TrainTrip;            //TrainTrip声明为Clock的友元类
public:
    void ShowTime();            //显示时间函数
    void SetTime(int h=0, int m=0, int s=0);      //带有缺省值的设置时间函数

    Clock(int h = 0, int m = 0, int s = 0);       //带有缺省值的构造函数

private:
    int m_hour;         //小时
    int m_minute;       //分钟
    int m_second;       //秒
};

void Clock::ShowTime()
{
    std::cout << this->m_hour << "  :" << this->m_minute << "  :" << this->m_second << std::endl;
}

void Clock::SetTime(int h , int m, int s)
{
    this->m_hour = h;
    this->m_minute = m;
    this->m_second = s;
}

Clock::Clock(int h, int m, int s)
{
    this->m_hour = h;
    this->m_minute = m;
    this->m_second = s;
}

class TrainTrip
{
public:
    TrainTrip(char* No, Clock S, Clock E);          //构造函数
    Clock  TripTime();
private:
    char* m_TrainNo;         //车次
    Clock m_StartTime;        //出发时间
    Clock m_EndTime;          //到达时间
};

TrainTrip::TrainTrip(char* No, Clock S, Clock E)
{
    this->m_TrainNo = No;
    this->m_StartTime = S;
    this->m_EndTime = E;
}

Clock TrainTrip::TripTime()
{
    int tmpH;
    int tmpM;
    int tmpS;
    int carry = 0;
    Clock tmpTime;
    if ((tmpS=this->m_EndTime.m_second - this->m_StartTime.m_second) > 0)
    {
        carry = 0;
    }
    else
    {
        tmpS += 60;
        carry = 1;
    }

    if ((tmpM = this->m_EndTime.m_minute - this->m_StartTime.m_minute-carry) > 0)
    {
        carry = 0;
    }
    else
    {
        tmpM += 60;
        carry = 1;
    }


    if ((tmpH = this->m_EndTime.m_hour - this->m_StartTime.m_hour - carry) > 0)
    {
        carry = 0;
    }
    else
    {
        tmpH += 24;
        
    }
    tmpTime.SetTime(tmpH, tmpM, tmpS);
    return tmpTime;

}

int main()
{
    Clock c1(8, 10, 10), c2(6, 1, 2);
    Clock c3;
    TrainTrip t1((char*)"G663",c1, c2);
    c3 = t1.TripTime();
    c3.ShowTime();
    return 0;
}

结果如下图所示:
在这里插入图片描述

★总结

  • 友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
  • 友元函数不能用const修饰。
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数。
  • 友元函数的调用与普通函数的调用和原理相同。
  • 友元关系是不能传递的,B类是A类的友元,C类是B类的友元,在C类和A类之同,如果没有声明,就没有任何友元关系,就不能进行数据共享。
  • 友元关系是单向的,如果声明B类是A类的友元,B类的成员函数就可以访同A类的私有和保护数据,但A类的成员函数不能访问B类的私有和保护数据。
  • 在使用友元时必须要慎重,要具体问题具体分析,要在提高效率和增加共享之间把我好一个,要在共享时和封装之间进行恰当的平衡。
    在这里插入图片描述

END...

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值