C++基础——运算符重载友元函数示例
一、前言
其实本人学习C++的目的,只是为了体会OOP设计思想,并为利用System Verilog验证复杂设计做准备。如果想要真正做点软件方面项目级的东西,还需要掌握其他高级语言和库、框架等知识。因此该系列博文仅注重语言基础和设计思想。上一篇该系列博文讲述了C++中基本的类封装,这次利用运算符重载友元函数来体会下C++的灵活性。
二、运算符重载友元函数
本文同样以《C++ Primer Plus》中的一个简单示例来讲解此内容。场景如下:时间粗劣地分为时和分两部分。需要完成两个时间的相加、时间与倍数的相乘(这个操作不太恰当,凑活看吧)以及显示时间操作。先上代码:
类声明:
#ifndef MYTIME_H_
#define MYTIME_H_ using std::ostream; class Time
{
private:
int hours;
int minutes;
public:
Time();
Time(int h,int m=);
void Reset(int h = ,int m = );
Time operator+(const Time& t) const;
Time operator*(double mult) const;//成员函数 friend Time operator*(double m,const Time& t) //友元函数(inline)
{return t * m;}
friend ostream& operator<<(ostream & os,const Time& t);//<<左侧必须是ostream对象 返回ostream&
};
#endif
mytime.h
类方法定义:
#include <iostream>
#include "mytime.h" Time::Time()
{
hours = minutes = ;
} Time::Time(int h,int m)
{
hours = h;
minutes = m;
} 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 / ;
sum.minutes %= ;
return sum;
} Time Time::operator*(double mult) const
{
Time result;
long totalminutes = hours * mult * + minutes * mult;
result.hours = totalminutes / ;
result.minutes = totalminutes % ;
return result;
} ostream& operator<<(ostream& os,const Time& t)
{
os << t.hours << " hours, " << t.minutes << " minutes";
return os;
}
mytime.cpp
以上代码的设计原则是:想让Time类对象的相加、与常数相乘以及打印操作与C++内置类型一致。因此+、*、<<三个符号必须进行运算符重载操作,即对此类对象使用这三个运算符时的具体实现细节需重新定义。声明格式为:<返回值类型> operator<op>()。但是这里存在一个问题,成员函数Time operator*(double mult) 在被调用时,类对象必须放置在*符号左侧,也就是说当表达式为m*t(t为Time类对象)时,编译器会报错。使用<<运算符打印Time类对象时同样会遇到此问题。
为了实现用户友好,使用没有此限制的友元函数重载运算符是个不错的选择。友元函数是类接口的扩展,这类函数虽然不是类成员函数,但可以访问类私有成员。需要注意的一点是:<<输出数据时,左侧必须是ostream类对象。因此重载<<运算符时,必须使函数返回参数中ostream类对象本身才能正确编译cout << A << B;语句。这条语句与(cout << A) << B;等同。
三、应用程序及结果分析
应用程序示例代码:
#include <iostream>
#include "mytime.h" using std::endl; int main()
{
using std::cout; Time planning;
Time coding(,);
Time fixing(,);
Time total;
Time adjusted1,adjusted2; cout << "planning time = ";
cout << planning << endl; cout << "coding time = ";
cout << coding << endl;
cout << "fixing time = ";
cout << fixing << endl;
cout << endl; total = coding + fixing;
cout << "coding + fixing = ";
cout << total << endl; adjusted1 = total * 1.5;//调用成员函数
cout << "total * 1.5 = ";
cout << adjusted1 << endl; adjusted2 = 1.5 * total;//调用友元函数
cout << "1.5 * total = ";
cout << adjusted2 << endl; }
usetime.cpp
Time类对象planning创建时隐式调用用户定义默认构造函数,而coding和fixing因有参数传递调用第二个构造函数,这正是C++的多态性质。可以看到,打印Time类对象与打印C++内置类型对象无异。重点关注“*”运算符的使用,adjusted1和adjusted2表达式中乘法运算依次调用了成员函数和友元函数。C++编译器同样会自动识别用户的意图。打印结果如图:

应用程序运行正确,重载的两个Time类对象的加法运算和Time类对象与常数的乘法运算结果无误。之后的两篇博客依次讲述动态内存分配与类继承内容,有错误的地方欢迎指正。
C++基础——运算符重载友元函数示例的更多相关文章
- C++第五次作业--运算符重载和函数重载
C++ 运算符重载和函数重载 C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载. 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是 ...
- 【C++基础 05】友元函数和友元类
友元是一种定义在类外部的普通函数或类,但它须要在类体内进行说明,为了与该类的成员函数加以差别,在说明时前面加以keywordfriend. 友元不是成员函数,可是它能够訪问类中的私有成员. 友元的作用 ...
- python 基础——运算符重载
方法 重载 调用 __init__ 构造函数 x = Class() __del__ 析构函数 del x __str__ 打印 print x __call__ 调用函数 x(*args) __ge ...
- C++运算符重载(友元函数方式)
我们知道,C++中的运算符重载有两种形式:①重载为类的成员函数(见C++运算符重载(成员函数方式)),②重载为类的友元函数. 当重载友元函数时,将没有隐含的参数this指针.这样,对双目运算符,友元函 ...
- C++:运算符重载函数之"++"、"--"、"[ ]"、"=="的应用
5.2.5 "++"和"--"的重载 对于前缀方式++ob,可以用运算符函数重载为: ob.operator++() //成员函数重载 或 operator++ ...
- C++ 类模板二(类模版与友元函数)
//类模版与友元函数 #include<iostream> using namespace std; template<typename T> class Complex{ p ...
- C++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数
(根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 对运算符重载的函数有两种处理方式:(1)把运算符 ...
- c++入门之—运算符重载和友元函数
运算符重载的意义是:将常见的运算符重载出其他的含义:比如将*重载出指针的含义,将<<与cout联合使用重载出输出的含义,但需要认识到的问题是:运算符的重载:本质仍然是成员函数,即你可以认为 ...
- C++运算符重载三种形式(成员函数,友元函数,普通函数)详解
首先,介绍三种重载方式: //作为成员函数重载(常见) class Person{ Private: string name; int age; public: Person(const char* ...
随机推荐
- 【线程系列五】什么时候释放锁—wait()、notify()
由于等待一个锁定线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不需要锁的时候及时释放锁是很重要的.在以下情况下,持有锁的线程会释放锁: 1. 执行完同步代码块. 2. 在执行 ...
- HTTP 前端需明白的相关知识点
简介: http(Hyper Text Transfer Protocol)超文本传输协议是万维网应用层的协议,使用了面向连接的TCP作为运输层协议. 特征: 简单快速:通过url就可以访问资源,协议 ...
- 【SpringMVC】从Fastjson迁移到Jackson,以及对技术选型的反思
为什么要换掉fastjson 直接原因是fastjson无法支持注解形式的自定义序列化和反序列化,虽然其Github上的Wiki上说明是支持的.但是实测结果表明:Test类的序列化被fastjson的 ...
- Securing Spring Cloud Microservices With OAuth2
From Zero to OAuth2 in Spring cloud Today I am presenting hours of research about a (apparently) sim ...
- Spring MVC 的 Java Config ( 非 XML ) 配置方式
索引: 开源Spring解决方案--lm.solution 参看代码 GitHub: solution/pom.xml web/pom.xml web.xml WebInitializer.java ...
- FPGA学习笔记(四)——Verilog基本语法
###### [该随笔部分内容转载自小梅哥] ######### 组合逻辑: 多路选择器.加法器.译码器.乘法器 时序逻辑: 计数器.分频器.定时器.移位寄存器 一.Verilog文件的基 ...
- 试试看读一下Zepto源码
在浏览器上(Safari.Chrome和Firefox)上开发页面应用或者构建基于html的web-view本地应用,你如PhoneGap,使用Zepto是一个不错的选择. Jquery和Zepto的 ...
- python 3.6 lxml标准库lxml的安装及etree的使用注意
据我所知,python 3.5之后的lxml模块里面不再包含etree,那么要怎么解决这个问题呢? lxml模块下的etree函数的使用问题,部分lxml模块不再支持etree方法,因此只能想办法下载 ...
- java基础小项目练习之1----3天做出飞机大战
Shoot射击游戏第一天一. 关键问题(理论):1. 简述FlyingObject.Enemy.Award.Airplane.Bee.Bullet.Hero之间的继承与实现关系2. 简述Hero类构造 ...
- 改造MIP获得搜索青睐,轻松完成SEO
搜索引擎目标及页面排序方法 搜索引擎作为互联网流量的入口,承担着流量分发的职责.但排序成千上万的网页,决定哪些网页在第一页,是由网页本身的用户体验决定的.权重算法会从内容优质性,广告多少,加载速度等多 ...