回头看我们之前的 rational.cpp,你满意了吗?反正我是觉得那些代码的可读性仍然欠佳:main 函数里边要多次调用 print 方法才能实现分数打印,酱紫不行!

如何通过重载 << 操作符来实现 print 打印分数的功能。( <<官方叫插入器 )

你或许知道,或许不知道,从第一次输出值开始,<< 操作符就一直被重载!

例如:std::cout << “Hello FishC!”;

C 标准库对左移操作符(<<)进行了重载,让它可以把值发送到一个流去(流的概念)。 但是在这个栗子中,iostream 库对新的 Rational 类表示一无所知,所以不能直接用 << 来输出我们的有理数(分数)。 但是,没有什么能够阻挡我们重载 << 操作符来让它接受 Rational 对象的宏伟愿望!

另外一个原因也比较重要:因为,重载的含义本身就是可以用相同的名字去实现不同的功能:输入参数方面有所差异就不会有问题。当然,我们无法在现有的 ostream 类里专门添加一个新的 operator <<()方法。所以我们只能定义一个正常的函数在外部重载这个操作符,这与重载方法的语法大同小异,唯一的区别是不再有一个对象可以用来调用 << 重载函数,而不得不通过第一个输入参数向这个重载方法传递对象。注意区别前边我们对四则运算符的重载。

下面是一个 operator <<()函数的原型:

std::ostream& operator<<( std::ostream& os, Rational f );
  • 第一个输入参数 os 是将要向它写数据的那个流,它是以“引用传递”方式传递的。
  • 第二个输入参数是打算写到那个流里的数据值,不同的 operator <<()重载函数就是因为这个输入参数才相互区别的  
  • 返回类型是 ostream 流的引用。一般来说,在调用 operator <<()重载函数时传递给它的是哪一个流,它返回的就应该是那个流的一个引用。

好了,介绍就说这么多,我们对 Rational.cpp 进行改造吧:Rational2.cpp

#include <iostream>
#include <string>
#include <stdlib.h> class Rational
{
public:
Rational(int num, int denom); // num = 分子, denom = 分母 Rational operator+(Rational rhs); // rhs == right hand side
Rational operator-(Rational rhs);
Rational operator*(Rational rhs);
Rational operator/(Rational rhs); private:
void normalize(); // 负责对分数的简化处理 int numerator; // 分子
int denominator; // 分母 friend std::ostream& operator<<(std::ostream& os, Rational f);
}; Rational::Rational(int num, int denom)
{
numerator = num;
denominator = denom; normalize();
} // normalize() 对分数进行简化操作包括:
// 1. 只允许分子为负数,如果分母为负数则把负数挪到分子部分,如 1/-2 == -1/2
// 2. 利用欧几里德算法(辗转求余原理)将分数进行简化:2/10 => 1/5
void Rational::normalize()
{
// 确保分母为正
if( denominator < 0 )
{
numerator = -numerator;
denominator = -denominator;
} // 欧几里德算法
int a = abs(numerator);
int b = abs(denominator); // 求出最大公约数
while( b > 0 )
{
int t = a % b;
a = b;
b = t;
} // 分子、分母分别除以最大公约数得到最简化分数
numerator /= a;
denominator /= a;
} // a c a*d c*b a*d + c*b
// - + - = --- + --- = ---------
// b d b*d b*d = b*d
Rational Rational::operator+(Rational rhs)
{
int a = numerator;
int b = denominator;
int c = rhs.numerator;
int d = rhs.denominator; int e = a*b + c*d;
int f = b*d; return Rational(e, f);
} // a c a -c
// - - - = - + --
// b d b d
Rational Rational::operator-(Rational rhs)
{
rhs.numerator = -rhs.numerator; return operator+(rhs);
} // a c a*c
// - * - = ---
// b d b*d
Rational Rational::operator*(Rational rhs)
{
int a = numerator;
int b = denominator;
int c = rhs.numerator;
int d = rhs.denominator; int e = a*c;
int f = b*d; return Rational(e, f);
} // a c a d
// - / - = - * -
// b d b c
Rational Rational::operator/(Rational rhs)
{
int t = rhs.numerator;
rhs.numerator = rhs.denominator;
rhs.denominator = t; return operator*(rhs);
} std::ostream& operator<<(std::ostream& os, Rational f);//函数声明 int main()
{
Rational f1(2, 16);
Rational f2(7, 8); // 测试有理数加法运算
std::cout << f1 << " + " << f2 << " == " << (f1+f2) << "\n"; // 测试有理数减法运算
std::cout << f1 << " - " << f2 << " == " << (f1-f2) << "\n"; // 测试有理数乘法运算
std::cout << f1 << " * " << f2 << " == " << (f1*f2) << "\n"; // 测试有理数除法运算
std::cout << f1 << " / " << f2 << " == " << (f1/f2) << "\n"; return 0;
} std::ostream& operator<<(std::ostream& os, Rational f)
{
os << f.numerator << "/" << f.denominator;
return os;
}

  

重载<<操作符的更多相关文章

  1. 《精通C#》索引器与重载操作符(11.1-11.2)

    1.索引器方法结构大致为<modifier><return type> this [argument list],它可以在接口中定义: 在为接口声明索引器的时候,记住声明只是表 ...

  2. C++ 重载操作符与转换

    <C++ Primer 4th>读书笔记 重载操作符是具有特殊名称的函数:保留字 operator 后接需定义的操作符号. Sales_item operator+(const Sales ...

  3. 解释清楚c++的重载操作符【用自己的话,解释清楚】

    C++中对于内置的变量及标准库中常见的类定义类常见的操作符含义,对于自定义的类也可以通过关键字operate 重载操作符的含义. C++中支持重载的目的 诚然操作符的重载可以通过使用函数实现同样的功能 ...

  4. 重载操作符 operator overloading 学习笔记

    重载操作符,只是另外一种调用函数的方法和表现方式,在某些情况它可以让代码更简单易读.注意不要过度使用重载操作符,除非它让你的类更简单,让你的代码更易读. 1语法 如下: 其中友元,关键字不是必须的,但 ...

  5. [019]转--C++ operator关键字(重载操作符)

    原博客:http://www.cnblogs.com/speedmancs/archive/2011/06/09/2076873.html operator是C++的关键字,它和运算符一起使用,表示一 ...

  6. VC6.0中重载操作符函数无法访问类的私有成员

    整理日: 2015年03月18日 在 C++ 中,操作符(运算符)可以被重载以改写其实际操作.同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成 ...

  7. C++高精度运算类bign (重载操作符)

    大数据操作,有例如以下问题: 计算:456789135612326542132123+14875231656511323132 456789135612326542132123*14875231656 ...

  8. C++ operator关键字(重载操作符)(转)

    operator是C++的关键字,它和运算符一起使用,表示一个运算符函数,理解时应将operator=整体上视为一个函数名. 这是C++扩展运算符功能的方法,虽然样子古怪,但也可以理解:一方面要使运算 ...

  9. C++中operator关键字(重载操作符)

    operator是C++的关键字,它和运算符一起使用,表示一个运算符函数,理解时应将operator=整体上视为一个函数名. 这是C++扩展运算符功能的方法,虽然样子古怪,但也可以理解:一方面要使运算 ...

  10. C++ Primer 学习笔记_60_重载操作符与转换 --赋值、下标、成员訪问操作符

    重载操作符与转换 --赋值.下标.成员訪问操作符 一.赋值操作符 类赋值操作符接受类类型形參,通常该形參是对类类型的const引用,但也能够是类类型或对类类型的非const引用.假设未定义这个操作符, ...

随机推荐

  1. python数据库的增删改查

    #coding=utf- from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlal ...

  2. 如何将一个Maven项目转化成一个Eclipse项目

    有时候我们需要将一个Maven项目导入到Eclipse中,直接作为一个普通的eclipse项目来导入是不行的,我们可以通过一个命令来实现:mvn eclipse:eclipse 1. 进入该Maven ...

  3. HTML6即将到来,你没有看错是HTML6

    HTML6提案1:对视频对象的更多控制 我们可能永远不会解决与压缩编解码器的争斗,但我们可以与之配合.不同的压缩算法可能需要更多的工作来实现,但是它们提供竞争.能对展现在页面上的视频帧提供更多控制的方 ...

  4. Animation 把动画片段拖入Animation组件里后不能播放

    1. 选中动画片段,点击右上角三道横杠那个按钮,选择Debug: 2.选择Legacy,然后再点击那个三道横岗的按钮,选择Normal就可以用了应该.

  5. (转)cut命令详解

    Linux:cut命令详解   cut 文件内容查看 显示行中的指定部分,删除文件中指定字段 显示文件的内容,类似于下的type命令. 说明 该命令有两项功能,其一是用来显示文件的内容,它依次读取由参 ...

  6. Git 设置 Hook

    Git 设置 hook Hook 就是钩子,在需要的时候调用,根据每个钩子脚本(函数)的返回值决定下一步的操作. 在使用 Git 的过程中,有时候需要定制 Git 以便满足实际的需求. 需求 在一个项 ...

  7. Scroller类的使用总结

    Scroll类之所以不好理解是因为没有搞清楚View的绘制流程. 1)简单来讲 viewgroup重绘时依次会调用  dispatchDraw -- drawChild --child.compute ...

  8. Excel 解析 (大文件读取)BingExcel

    最近在整理一个excel读取与写出的orm框架.使用的saxreader方式,支持百万级别的excel读取. 并且在通常使用中提供了监听的读取方式.如感兴趣的朋友可以稍微了解下 ,项目地址https: ...

  9. Android无需权限显示悬浮窗

    TYPE_TOAST一直都可以显示, 但是用TYPE_TOAST显示出来的在2.3上无法接收点击事件, 因此还是无法随意使用. 下面是我之前研究后台线程显示对话框的时候记得笔记, 大家可以看看我们项目 ...

  10. 《ArcGIS Runtime SDK for Android开发笔记》——(8)、关于ArcGIS Android开发的未来(“Quartz”版Beta)

    1.前言 今天再一次在官网看到了ArcGIS Runtime SDK for Android下一个版本“Quartz”版的更新资料,它将是一个非常重要的更新,包括API接口的重构和开发思路的调整.具体 ...