C++突破封装:友元和内部类

首先来看一个Date类,当我们想要重载实现 operator<< 和 operator>> 一般会在类的内部写:

class Date
{
public:
    ostream& operator<<(const ostream& out)
    {
        out << _year << "-" << _month << "-" << _day;
        return out;
    }
    
    istream& operator>>(istream& in)
    {
        in >> _year >> _month >> _day;
        return in;
    }
private:
    int _year;
    int _month;
    int _day;
};

但是这样会存在一个问题,类中 this指针 隐含的存在于成员函数的第一个形参位置,在调用 operator<< 和 operator>> 的时候,就要反着写,逻辑上很别扭,不符合我们的直观使用。

    Date d3;
    d3 >> cin;
    d3 << cout << endl;
    return 0;

解决方案:只可以把 operator<< 和 operator>> 写在类外,这样不存在this指针,就可以显示的写出形参:类类型对象。可是在类外就不能访问到类中的私有成员变量,这时候就必须用到友元函数。

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

友元函数

  • 友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装。
  • 友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

如下代码就给出了重载 operator<< 和 operator>> 的正确逻辑写法:

#include <iostream>
using namespace std;

class Date
{
    //声明友元函数
    friend ostream& operator<<(ostream& out, const Date& d);
    friend istream& operator>>(istream& in, Date& d);
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }

    void Print()
    {
        cout << _year << "-" << _month << "-" << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

//定义友元函数
ostream& operator<<(ostream& out, const Date& d)
{
    out << d._year << "-" << d._month << "-" << d._day;
    return out;
}

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

int main()
{
    Date d1(2020, 6, 7);
    d1.Print();
    cout << d1 << endl;
    operator<<(cout, d1) << endl;
    Date d2(2020, 6, 8);
    cout << d1 << " " << d2 << endl;

    Date d3;
    cin >> d3;
    cout << d3 << endl;
    return 0;
}

友元类

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

如下代码:Date类为Time类的友元类,则在Date类中可以访问Time类中的私有成员变量

#include <iostream>
using namespace std;

class Time
{
    //声明日期类为时间类的友元类
    friend class Date;
public:
    Time(int hour = 0, int minute = 0, int second = 0)
    {
        _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 SetTime(int hour, int minute, int second)
    {
        //this->_t._hour = hour;
        //this->_t._minute = minute;
        //this->_t._second = second;
        _t._hour = hour;
        _t._minute = minute;
        _t._second = second;
    }

    void Print()
    {
        cout << _year << "-" << _month << "-" << _day << endl;
        //cout << this->_t._hour << "-" << this->_t._minute << "-" << this->_t._second << endl;
        cout << _t._hour << "-" << _t._minute << "-" << _t._second << endl;
    }
private:
    int _year;
    int _month;
    int _day;
    Time _t;
};

int main()
{
    Date d1(2020, 6, 7);
    d1.Print();
    d1.SetTime(12, 44, 0);
    d1.Print();
    return 0;
}

内部类

  • 内部类天生是外部类的友元类
  • 内部类可以通过外部类的对象来访问外部类中的所有成员
  • 定义内部类的对象时必须指定它的作用域是在外部类
#include <iostream>
using namespace std;

class A
{
public:
    A(int x = 1, int y = 2)
    {
        _x = x;
        _y = y;
    }

    //B类天生就是A类的友元类
    class B
    {
    public:
        void Print(const A& a)
        {
            cout << a._x << " " << a._y << endl;
        }
    };
private:
    int _x;
    int _y;
};

int main()
{
    //定义B类的对象时必须指定它的作用域是在A类
    A::B b; 
    b.Print(A());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值