7.4友元

友元

我们来看最初的Sales_data版本。

struct Sales_data {
    Sales_data() = default;                      //自定义的默认构造函数
    Sales_data(const string& s) :_bookNo(s) {}   //有参构造函数
    Sales_data(const string& s, unsigned n, double p) :
        _bookNo(s), _sold(n), _revenue(p) {}	//有参构造函数
    Sales_data(const Sales_data& rhs) :          //拷贝构造函数
        _bookNo(rhs._bookNo),
        _sold(rhs._sold),
        _revenue(rhs._revenue) {}
    Sales_data& combine(const Sales_data&);     //+=
    double avgPrice()const;                     //求平均价格
    string _bookNo;
    unsigned _sold = 0;         //类内初始值
    double _revenue = 0.0;       //类内初始值
};
Sales_data& Sales_data::combine(const Sales_data& rhs) {
    _sold += rhs._sold;
    _revenue += rhs._revenue;
    return *this;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs) {
    Sales_data sum = lhs;
    sum.combine(rhs);
    return sum;
}
double Sales_data::avgPrice()const {
    if (_sold)
        return _revenue / _sold;
    else
        return 0;
}
ostream& print(ostream& os, const Sales_data& s) {
    os << s._bookNo << "	" << s._sold << "	"
        << s.avgPrice() << "	" << s._revenue << endl;
    return os;
}
istream& read(istream& is, Sales_data& item) {
    double price = 0;
    is >> item._bookNo >> item._sold >> price;
    item._revenue = price * item._sold;
    return is;
}

此时,Sales_data的数据成员都是public可访问的,非类内函数可以直接访问到类中的数据成员。但经过封装之后,数据成员编程private,我们的read、print和add函数就无法正常编译了。

*类可以允许其他类或者函数访问它的私有成员,方法是用友元令其他类或者函数成为它的友元。

友元一共有三种实现方法:全局函数做友元、类做友元、成员函数做友元。

1.成员函数做友元

如果把一个全局函数作为类的友元,只要在类中任意位置增加一个friend关键字开始的函数声明即可。一般来说,最好在类定义的开始集中声明友元

下面我们利用友元技术将上述封装后的Sales_data实现。

class Sales_data {
    public:
    //类开头集中声明友元
    friend Sales_data add(const Sales_data& lhs, const Sales_data& rhs);
    friend ostream& print(ostream& os, const Sales_data& s);
    friend istream& read(istream& is, Sales_data& item);
    
    Sales_data() = default;                      //自定义的默认构造函数
    Sales_data(const string& s) :_bookNo(s) {}   //有参构造函数
    Sales_data(const string& s, unsigned n, double p) :
        _bookNo(s), _sold(n), _revenue(p) {}	//有参构造函数
    Sales_data(const Sales_data& rhs) :          //拷贝构造函数
        _bookNo(rhs._bookNo),
        _sold(rhs._sold),
        _revenue(rhs._revenue) {}
    Sales_data& combine(const Sales_data&);     //+=
    double avgPrice()const;                     //求平均价格
    
    private:
    string _bookNo;
    unsigned _sold = 0;         //类内初始值
    double _revenue = 0.0;       //类内初始值
};
Sales_data& Sales_data::combine(const Sales_data& rhs) {
    _sold += rhs._sold;
    _revenue += rhs._revenue;
    return *this;
}
Sales_data add(const Sales_data& lhs, const Sales_data& rhs) {
    Sales_data sum = lhs;
    sum.combine(rhs);
    return sum;
}
double Sales_data::avgPrice()const {
    if (_sold)
        return _revenue / _sold;
    else
        return 0;
}
ostream& print(ostream& os, const Sales_data& s) {
    os << s._bookNo << "	" << s._sold << "	"
        << s.avgPrice() << "	" << s._revenue << endl;
    return os;
}
istream& read(istream& is, Sales_data& item) {
    double price = 0;
    is >> item._bookNo >> item._sold >> price;
    item._revenue = price * item._sold;
    return is;
}

2.用类做成员函数

如果一个类制定了友元类,则友元类的成员函数可以访问此类包括非公由成员在内的所有成员。

考虑如下场景:你的房子有客厅、卧室,你有一个好朋友想参观你的房子,平常你只想给别人参观你的客厅不想被他参观你的卧室,但是他是你的好基友你可以给他看你的卧室。

思路:房子可以作为一个只有数据成员的类,类中有卧室和客厅两个数据成员。你的朋友作为一个类,这个类有一个成员函数有一个数据成员,参观的动作作为一个成员函数,参观的房子作为一个数据成员。

//main.cpp
#include<iostream>
using namespace std;
#include<string>
//房子类
class GoodGay;
class Building{
    friend GoodGay;
public:
    Building():_sittingRoom("客厅"),_bedRoom("卧室"){}
    string _sittingRoom;
private:
    string _bedRoom;
}//好基友类
class GoodGay{
public:
    GoodGay(){
        _build=new Building;
    }
    ~GoodGay(){
        delete _build;
    }
    string visit(){
        return _build->_bedRoom;
    }
    Building *_build;
}int main() {
    GoodGay g;
    cout << g.visit();
    return 0;
}

输出结果为:在这里插入图片描述注意在Building类定义之前声明了GoodGay类,是因为Building类中声明了GoodGay友元,编译器不知道GoodGay,所以需要在Building类之前声明GoodGay是个类。

3.令成员函数作为友元

要想令某个成员函数作为友元,如A类的成员函数f()想访问B类的数据成员,我们必须按如下方式设计程序

  • 先声明A类,定义B类,在b类中声明f(),但不能定义它。
  • 定义A类。
  • 定义clear。

在上述场景中,我们朋友想借住你的卧室,但你不想啊,所以你的朋友只能参观你的卧室,但不能住你的卧室。

#include<iostream>
using namespace std;

class Building;
class GoodGay{
public:

	GoodGay();
	void visit();//让visit函数可以访问Building中私有成员
	void visit2();//让visit2函数不可以访问Building中私有成员

	Building* building;
};

class Building{
	//告诉编译器 GoodGay类下的visit成员函数作为本类的好朋友,可以访问私有成员
	friend void GoodGay::visit();
public:
	Building();

	string m_SittingRoom;//卧室

private:
	string m_BedRoom;//卧室
};

//类外实现成员函数
Building::Building(){
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}
GoodGay::GoodGay(){
	building = new Building;
}
void GoodGay::visit(){
	cout << "visit函数正在访问:" << building->m_SittingRoom << endl;

	cout << "visit函数正在访问:" << building->m_BedRoom << endl;
}
void GoodGay::visit2(){
	cout << "visit函数正在访问:" << building->m_SittingRoom << endl;

	//cout << "visit函数正在访问:" << building->m_BedRoom << endl;
}
int main(){
	GoodGay gg;
	gg.visit();
	gg.visit2();
	system("pause");
	return 0;
}

输出结果为:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值