重载运算符与友元函数
来源:互联网 发布:javascript图形编程 编辑:程序博客网 时间:2024/05/20 13:08
本次博客 主要学习运算符重载和友元函数。其中
运算符重载能够将平时用于内置类型的变量的操作符(如+,-,*,/等)用于类对象;
友元这种C++机制使得非成员函数可以访问私有数据。
一、重载运算符
重载运算符,将普通运算符重载扩展到用户自定义类型,编译器根据具体环境来选用。(有点像重载函数—多态:函数名相同,但函数列表不同)这样做使代码看起来更加自然,同时隐藏了内部机理,强调了OOP的实质。
重载运算符,必须需要使用运算符函数的特殊函数格式,如下
operatorop(argument-list)
其中,op必须是有效的C++运算符。
重载运算符是怎样工作的?
理解重载运算符是怎样工作的?假定Time类,并为它定义一个operator+()成员函数,以重载+运算符,以便能够将两个Time类对象相加。等式:
T = t1 + t2 ;
编译器发现,操作数都是Time类对象,因此调用相应的运算符函数替换上述运算符:
T= t1. operator+( t2);
该函数隐式地使用了t1(因为它调用了方法),而显式地使用t2对象(因为它被作为参数传递)。
因此,在运算符表示法中,运算符左侧的对象(这里为t1)是调用对象,运算符右边的对象(这里为t2)是作为参数被传递的对象。
扩展
当两个以上的对象相加时,如何转化为函数调用
T = t1 + t2 +t3;
由于+是从左向右的运算符,因此,
T= t1. operator+( t2+t3); //第一步T= t1. operator+( t2. operator+(t3) );//第二步
二、友元函数的引入
在前面重载运算符的学习中,我们已经知道了,运算符左侧的操作数是调用对象,运算符右侧的操作数是参数。比如:
A = B * 2.75;
将被转换为下面的成员函数调用:
A = B.operator*(2.75);
可是下面的语句如何办呢?
A = 2.75 * B;
函数左侧是操作对象,而2.75不能作为操作对象,因此编译器不能使用成员函数调用来替换该表达式。
解决方案一:
告诉每个人只能用B*2.75这种格式写。显然这是一种对服务器友好,对客户需要当心的一种解决方案。
解决方案二:
对该重载运算符函数进行多态实现。
Time operator*(double m,const Time & t){ Return t * m; //use t.operator(m)}
解决方案三:
引入友元函数的思想来解决。
1)首先将该函数修改非成员函数。
对于非成员重载运算符函数来说,运算符表达式左边的操作数对应于运算符函数的第一个参数,运算符表达式右边的操作数对应于运算符函数的第二个参数。
2)引入友元函数
因此,此时使用非成员函数按所需的顺序获得操作数,2.75作为函数第一个参数,B作为第二个参数。但引发一个新问题:普通非成员函数不能直接访问类的私有成员,然而,有一类特殊的非成员函数可以访问类的私有成员,它们被称为友元函数。
格式:
friend Time operator*(double m,const Time & t)
该原型意味着:
- 虽然operator*()函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用。
- 虽然operator*()函数不是成员函数,但它与成员函数的访问权限相同。
总之,类的友元函数是非成员函数,其访问权限与成员函数相同。
注意,编写函数定义时,不能使用Time::限定符,不能加关键字friend。
三、代码部分
类的声明:
Time类提供了用于调整和重新设置时间、显示时间、将两个时间相加/减的方法; 构造函数; 友元函数的声明。
//mytime.h#ifndef MYTIME_H_#define MYTIME_H_#include <iostream>class Time{ private: int hours; int minutes; public: Time(); Time(int h,int m = 0); //构造函数 void AddMin(int m); void AddHr(int h); void Reset(int h = 0,int m = 0); Time operator+(const Time & t) const; Time operator-(const Time & t) const; Time operator*(double n) const; friend Time operator*(double m,const Time & t) { return t * m ;} //内联函数定义 friend std::ostream & operator<<(std::ostream &os, const Time & t);};#endif
类的定义
//mytime.cpp#include "mytime.h"Time::Time(){ hours = minutes = 0;}Time::Time(int h,int m){ hours = h; minutes = m;}void Time::AddMin(int m){ minutes += m; hours += minutes / 60; minutes %= 60; }void Time::AddHr(int h){ hours += h;}void Time::Reset(int h,int m){ hours = h; minutes = m;}Time Time::operator+(const Time & t) const{ Time sum; sum.minutes = minutes + t.minutes; sum.hours = hours + t.hours + sum.minutes /60; sum.minutes = sum.minutes % 60; return sum;}Time Time::operator-(const Time & t) const{ Time diff; int tot1,tot2; tot1 = t.minutes + t.hours * 60; tot2 =minutes + hours * 60; diff.hours = (tot2 -tot1) /60; //小时 diff.minutes = (tot2 -tot1) % 60;//分钟 return diff;}Time Time::operator*(double mult) const{ Time result; long totalminutes = hours * mult * 60 +minutes *mult; //总分钟 result.hours = totalminutes /60; result.minutes = totalminutes % 60; return result;}std::ostream & operator<<(std::ostream & os,const Time & t) { os << t.hours << " hours," << t.minutes <<" minutes"; return os; //对象本身返回还是对象,方便级联使用 }
类的使用
//usetime.cpp#include "mytime.h"#include <iostream>int main(){ using std::cout; using std::endl; Time t1(3,35); Time t2(2,48); Time temp; cout << "t1 and t2:\n"; cout << t1 <<"; " <<t2 <<endl; temp = t1 + t2; //利用重载符 operator+() cout << "t1+t2: "<<temp <<endl; temp = t1 - t2; //利用重载符 operator-() cout << "t1-t2: "<<temp <<endl; temp = t1 * 1.17; //利用重载符 operator*() 顺序 cout << "t1*1.17: "<<temp <<endl; temp = 1.17 * t1; //利用重载符 operator*() 逆序 cout << "1.17*t1: "<<temp <<endl; //利用重载符 operator<<()级联 cout << "10.0*t1: " <<10.0*t1<<"10.0*t2: " <<10.0*t2<<endl; return 0;}
截图:
注意:
1. 当总的分钟数超过59时,函数是通过整数除法和求模运算调整minutes和hours的值的。
2. 函数的参数是引用传递,目的是提高效率。传值也能实现,但是传递引用速度更快,使用的内存更少。
3. 函数的返回值不能是引用。返回对象将创建对象的副本,函数结束时虽然销毁了局部变量,而调用函数使用的是所构造的副本。然而,如果返回类型为引用,由于局部变量在函数结束时被删除,因此引用将指向一个不存在的对象。
因此,不要返回指向局部变量/临时对象的引用。函数执行完毕后,局部变量和临时对象将消失,引用将指向不存在的数据。
阅读全文
1 0
- 运算符重载与友元函数
- 重载运算符与友元函数
- C++运算符重载 成员函数与友元函数
- 浅谈运算符重载与友元函数
- 友元函数与运算符重载的结合
- c++ 运算符重载 友元函数
- 利用友元函数,重载运算符
- 友元函数重载运算符
- 运算符重载为友元函数
- 重载运算符以及友元函数
- 7.10友元函数重载运算符
- 运算符重载和友元函数
- 友元函数编写运算符重载
- 友元函数编写运算符重载
- C++ 重载运算符 友元函数
- C++运算符重载,友元函数
- 友元函数以及重载运算符
- 友元函数和运算符重载
- Windows下PostgreSQL安装与配置
- (多核DSP快速入门)7.利用SharedRegion的核间内存共享
- 第五章 第二节:数值运算符和函数
- Maven之(五)Maven仓库
- Bug严重度分类、测试结束标准、bug只出现一次的处理
- 重载运算符与友元函数
- table 操作——点击表格某一行获取这一行的某一个单元格
- 设计模式C++版:第二十式状态模式
- javabean为什么要实现序列化
- QT下简易画板实现
- nginx的那些事
- 状态压缩DP
- JavaScript 验证 API
- 玩转Google开源C++单元测试框架Google Test系列