4.3 对象与类(二)——友元函数

本文探讨了C++中的友元函数,它允许非成员函数访问类的私有成员,常用于重载运算符。以重载'<<'运算符为例,解释了为何需要友元函数,以及如何在不修改iostream库的情况下让Time类对象能被cout输出。同时,文章讨论了在选择成员函数还是非成员函数来重载运算符时的考虑因素。
摘要由CSDN通过智能技术生成

C++控制对类对象私有成员的访问,通常公有成员方法提供唯一的访问途径。但友元可以突破这一访问限制,其中友元函数虽非成员函数,让其称为类的友元,它的访问权限与公有成员函数相同。当为类重载二元运算符时,常常需要友元。因为不能保证二元运算符的参数都是该类的对象,这将限制该运算符的使用。例如A*B;(其中A是对象,B不是对象)转换为A.operator*(B),但是写成B*A会因为B不是对象无法调用而出错。这时,就可以通过非成员函数——友元函数来解决。

友元函数的原型例子:friend Time operator*(double, const Time &);,注意:

  • 虽然友元函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符调用
  • 虽不是成员函数,但是与成员函数的访问权限相同。
  • 因为不是成员函数,所以编写定义时,不要使用XXX::限定符,不要在定义中使用friend关键字。

对友元函数的理解:友元函数是类的扩展接口的组成部分,与类方法一起实现类接口的两种不同机制,虽然友元函数可以访问私有数据,但是还是由类声明决定哪个函数是友元,因此类声明仍然控制了哪些函数可以访问私有数据,不能认为友元违反OOP数据隐藏的原则。

#include <iostream>
using namespace std;
class Time{
    private:
        int hours;
	int minutes;
    public:                                // 成员函数使用内联函数
	Time(int _hours = 0, int _minutes = 0){
		hours = _hours;
		minutes = _minutes;
	}
	Time operator*(double n) const;
	friend Time operator*(double n, Time & t);
	void show()const{
		std::cout << hours << " hours," << minutes << " minutes" << std::endl;
	}		
};

int main(){
    Time t1(7,30);
    Time t2 = 3 * t1;    // 使用了友元函数
    Time t3 = t1 * 2;    // 使用成员函数
    t2.show();
    t3.show();
    return 0;
}
Time Time::operator*(double n) const
{
    Time res;
    int min = n * minutes + hours * n * 60;
    res.minutes = min % 60;
    res.hours = min / 60;
    return res;
}
//Time operator*(double n, Time & t){
//    Time res;
//    int min = n * t.minutes + t.hours * n * 60;
//    res.minutes = min % 60;
//    res.hours = min / 60;
//    return res;
//}
Time operator*(double n, Time & t){        // 1)处
    return t * n;
}

1)处: 用友元函数反转操作数顺序,让成员函数处理私有数据

1 常用的友元:重载<< 运算符

首先,<<运算符已经被重载多次了,一是作为位运算符,二是ostream对该运算符进行了重载,将其转换为一个输出工具,cout是一个ostream对象,能够识别c++所有的基本类型。要使cout识别Time对象,一个方法是将一个新的函数运算符定义到ostream类声明中,但修改iostream文件是个危险的主意。但可以通过Time声明让Time类知道如何使用cout。

friend ostream & operator<<(ostream &os, const Time &); // 函数原型

ostream & operator<<(ostream & os, const Time & t){            // 函数定义,注意返回值
    os << t.hours <<" hours," << t.minutes << " minutes" << endl;
}

Time类声明使operator<<()函数成为Time类的一个友元函数,但operator<<()函数并不是ostream类的友元,因为函数访问了Time类的私有成员,所以他是Time类的友元。

在重载运算符时,是选择成员函数还是非成员函数?对于很多运算符来说,可以选择使用成员函数或非成员函数来实现运算符重载,这样才能直接访问类的私有数据。在重载双目运算符时,主要的区别是,对于成员函数来说,一个操作数通过this指针隐式的传递,另一个通过函数参数显式地传递;对于友元函数来说,两个操作数都作为参数来传递。所以大部分情况下,在避免二义性错误,只能从中选择一个,这时没有多大差别,但某些运算符只能选择成员函数,在某些情况下选择非成员函数更好一些,如为类定义类型转换。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vinkuan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值