C++:使用类|| 运算符重载友元

Posted 赵同学的代码时间

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++:使用类|| 运算符重载友元相关的知识,希望对你有一定的参考价值。


C++中的运算符重载

C++中允许运算符重载,它使得我们可以更加灵活地使用标准C++运算符,使得他们可以实现更多的、更复杂的功能。


其实,运算符的重载我们早已接触许多。如,STL中map、bitset对[]运算符的重载,cout,cin 中对<<、>>运算符的重载,string中对+的重载,*在指针前表示取内容,在数字间确实乘法,等等,但是如何书写重载函数,重载函数的结构究竟是什么样子,这篇文章将会告诉你。


运算符重载是一种特殊形式的C++多态(类似于函数重载,同名,但实现不同功能)。


定义一个重载的格式:

关键字operator 标准C++运算符 (参数列表)

由以上三个部分组成。


引入一个实例:时间运算,我们早上花费在某事上t1=a小时b分钟,下午又花费在该事上t2=c小时d分钟,求总共花费的时间是多少,要求,设计一个运算符“+‘重载,能够直接计算t1 + t2;


为解决这个问题,我们声明一个Time类

#ifndef MYTIME1_H_#define MYTIME1_H_
class Time{ private: int hours; int minutes;
public: Time();//默认构造函数 Time(int h, int m = 0);//带初始化的构造函数 void Addmin(int m);//加m分钟 void Addhour(int h);//加h小时 void Reset(int h = 0, int m = 0);//重新设置时间 Time operator+(const Time& t) const;//关键,重载加法运算符 void Show()const;//展示时间};#endif

Time类中定义了许多常见的对时间的操作,然后再定义方法:

//实现头文件中声明的功能#include <iostream>#include "mytime1.h"
using namespace std;
Time::Time(){ hours = minutes = 0;}
Time::Time(int h, int m)//Time::Time(int h = 0, int m = 0)是错误的{ hours = h; minutes = m;}
void Time::Addmin(int m){ minutes += m; hours += minutes / 60; minutes %= 60;}
void Time::Addhour(int h){ hours += h;}
void Time::Reset(int h, int m){ hours = h; minutes = m;}
void Time::Show()const{ cout << hours << "hours, " << minutes << "minutes" << endl;}

在编写这段程序时发现一个细节:在方法存在默认值时,只能在声明中或者在定义中体现默认值,不能在两个地方同时体现,否则会报错。

重载运算符定义:

Time Time::operator+(const Time& t)const{ Time sum = *this; sum.Addmin(t.minutes); sum.Addhour(t.hours); return sum;}//重载运算符函数也是可以使用方法的。


t1+t2 +t3 合法吗?

合法。因为系统会判定为t1 + (t2 + t3), t2 + t3 返回Time类型,正好是我们想要的,所以该表达式是合法的。


重载有限制吗?

有,首先,重载中必须使用到自定义类型,避免重载标准运算符;其次,使用运算符时不能违背原先句法规则,原先是二元运算符,重载后依旧是二元运算符,不能一元使用;再次,不能创新,不能创造运算符,我们知道python中使用**表示幂,但你不能在C++中通过运算符重载得到**运算符表示幂。常见的运算符都可重载,其中,= 、()、 []、-> 只能通过成员函数的形式进行重载。


作为成员函数还是非成员函数?

一般来说,重载运算符既可作为成员函数亦可作为非成员函数,但是,作为非成员函数是通常设置为友元函数这样它再能访问到数据隐藏部分。


友元friend

假如你有一个知心朋友,那他偶尔用用你的东西,你总是不会拒绝的,在C++中,定义一个friend,那它,就能访问你所私有和保护的东西了。这就叫做友元,友元有三种:友元函数、友元类和友元成员函数


为什么需要友元?

假如我们定义了一个Time * const int 类型的运算符重载,我们这样使用固然没有问题,但是,倘若我们修改了他们的顺序,使用 const int * Time 就会出现问题,为了避免这个问题,我们还需要再重载一次*,再重载一次使用两个参数的*运算符,这必须是非成员函数,但非成员函数想要访问到private是会被拒绝的,于是友元应运而生。

Time B;B * 3 等于 B.operator*(2.75)(以成员函数方式调用)3 * B 等于 3.operator*(B)(由于3不是对象,会报错)故,定义friend Time operator*(int m, const Time & T);这样 3 * B 就会被处理为 operator*(3, B),会得到正确结果 


创建友元

创建友元的第一步,是要在类中表示它有这个朋友,即在类中完成声明

friend Time operator*(int m, const Time & T);

这样,定义函数的权限与成员函数相同,由于非成员函数,所以它定义时不能用作用域限定符。方法定义时,不需要加friend

Time operator*(int m, const Time& T){  return T * m; //use t.operator*(int m)}

友元是否违背了OOP?

有的小伙伴可能就会问了,有了友元,OOP开了这么大一个bug,这还OOP吗。答案是,还是OOP的,因为,友元也需要在类中声明,它相当于是经过”同意“的,既然是经过同意的,并不是随便就能访问的,那怎么会是bug呢。


友元是双向的吗?

结合实际生活就知道,朋友并不一定是双向的,有些仅仅是表面朋友,所以,友元类被声明后,友元类可以访问类隐藏内容,而类不能访问友元类隐藏内容,若要双向访问,需要双向声明。


友元类和友元成员函数更为复杂,以后再讲。


以上是关于C++:使用类|| 运算符重载友元的主要内容,如果未能解决你的问题,请参考以下文章

类模板 友元重载形式 各种运算符重载 new delete ++ = +=

关于C++运算符重载和友元的概念

C++运算符重载中 重载为类的成员函数和重载为类的友元函数 的区别是啥?

❥关于C++之成员与友元函数重载运算符

C++笔记--面向对象(OOP)编程基础--操作符重载及友元

C++入门不能重载为友元函数的4个运算符(=, ->, [ ], ( ))