1. 重载<< 和>>运算符

<<和<<运算符可以被重载用于输入输出操作,在上一节中,我们对Rational对象进行输出时定义了toString()类成员函数。如何通过cout << r 直接输出Rational对象:

对于: r1 + r2,   r1, r2和+都是Rational类的实例,因此,+可以被作为成员函数重载:

但是,对于cout << r 语句,运算符<< 有两个算子cout, r. cout 是ostream类的实例, r是rational类的实例,两个算子属于不同的类型,因此,<<不能作为类的成员函数被重载!

通过在Rational类中定义友元函数operator<<(),对<<进行重载,这时operator<<()便可以访问Rational类中的私有成员

在rational.h中定义友元函数:

// 重载流插入运算符<<
// 对于cout << r 语句,等同于operator<<(cout, r), 运算符<< 有两个算子cout, r.
//cout 是ostream类的实例, r是rational类的实例,因此,<<不能作为类的成员函数被重载!
// 通过将operator<<函数定义为友元函数,访问Rational类中的私有成员
// 返回的是ostream类型的引用, 因为<<运算符可能会以链的形式表示 cout<<r1<<r2 相当于(cout<<r1)<<r2
friend ostream& operator<<(ostream& out, const Rational& rat);  

main.cpp中友元函数的实现按:

// 友元函数operator<< 的实现
ostream& operator<<(ostream& out, const Rational& rat)
{out << rat.numerator << "/" << rat.denominator << endl;return out;
}

实现了对<<运算符的重载:

cout << "r1+r1 = " << rat1+rat2 << endl;

2.自动类型转换:

有时,会进行 int+double的计算,这是由于c++中可以进行类型的自动转换。

能否对 rational  + int 或者rational + rat 进行自动类型转换, 可以!

需要定义一个运算符函数,它能将一个有理数转化为in或者double类型,这种函数没有返回值,定义如下:

rational.h文件:

// 自动类型转换
// 定义运算符函数 operator double()
// 运算符函数是一个特殊的函数,他以opeator关键字开头,函数名是类型的名称,
// 没有返回值 ,当然也没有参数
operator double();
// 定义 operator int()运算符函数
//operator int(); 

rational.cpp文件

// 实现运算符函数
Rational::operator double()
{return get_floatValue();
} //Rational::operator int()
//{
//  return get_intValue();
//}

数值到rational类型的转换可以通过构造函数实现

Rational::Rational(int numerator)
{this->numerator = numerator;this->denominator = 1;
}

注: 一个类中可以定义转换函数实现从对象到基本数据类型的转换,也可以定义一个构造函数实现基本数值类型到对象的转换。

但在一个类中,两者不能同时存在:

一个问题: C++可以实现一定的自动类型转换。可以通过定义函数实现这种转换:

可以实现 r1+3.4

但是对于 3.4+ r1这种运算,编译器会报错:
在这里,+运算符并不是对称的,+左边的算子是+运算符的调用者,所以必须是一个Rational对象:

如何实现 3.4+ r1:

1.定义Rational(int num)类:

2.将+运算符重载定义为类的非成员函数:

-----------------------------------------------------------------------------------------------------------------------------------------

2.带有重载运算符的函数的Rational类

总结:(书本)

1.在同一个类中,从基本数据类型到类的转换函数,和从类到基本数据类型的转换函数不能同时出现在一个类里面,否则会出现二义性错误,因为这个时候编译器不知道执行哪一个转换函数,通常,从基本数据类型到类的转换函数更有用。

2. 大部分运算符既可以以成员函数的形式,也可以以非成员函数的形式重载,但是,=,【】,->,()只能以成员函数的形式重载,<<和>>只能以非成员函数的形式重载

3.如果希望返回对象是左值,那么函数返回值应该定义为引用,赋值运算符,+=,-=,*=,/=,%=,以及前缀++和前缀--,【】

依据上面的三条原则对 Rational类的重写:

更改:

将部分成员函数改编变为非成员函数,实现一些运算符的左右对称:
rational_new.h文件

#ifndef RATIONAL_NEW_H
#define RATIONAL_NEW_H
#include <iostream>
#include <string>using namespace std;
class Rational_new
{private:int numerator;int denominator;static int gcd(int a, int b);public:Rational_new();   // 无参构造函数Rational_new(int numerator, int denominator);Rational_new(int n);   // 只有一个参数的构造函数int get_numerator() const;int get_denominator() const;// 定义对象的加减乘除 Rational_new add(const Rational_new& rat) const;   Rational_new subtract(const Rational_new& rat) const;Rational_new multiply(const Rational_new& rat) const;Rational_new divide(const Rational_new& rat) const;// 比较对象的大小, 返回值{-1,0,1} int compareTo(const Rational_new& rat) const;//  判断对象相等 bool equalTo(const Rational_new& rat);int get_intValue() const;double get_doubleValue() const;// 将对象转化为字符串 string get_string() const;// 重载运算符+=, -=, *=, /=运算符,这些是左值运算符,且以成员函数的形式实现Rational_new& operator+=(const Rational_new& rat);Rational_new& operator-=(const Rational_new& rat);Rational_new& operator*=(const Rational_new& rat); Rational_new& operator/=(const Rational_new& rat);// 重载[]运算符,同样也是左值运算符,且以成员函数的形式实现int& operator[](int index);      //重载前缀加和前缀减运算符,即--a,--b, 无参函数 Rational_new& operator++();Rational_new& operator--();// 重载后缀加和后缀减,即a--,a++, 伪参数 Rational_new operator++(int dummy);Rational_new operator--(int dummy);// 重载+-运算符,正负,无参数Rational_new operator+();Rational_new operator-(); // 重载流提取运算符和流插入运算符 ,定义友元函数进行实现 friend ostream& operator<<(ostream&, const Rational_new& rat); };// 以非成员函数的形式实现关系运算符及+,-,*,/的重载
bool operator<(const Rational_new& rat1, const Rational_new& rat2);
bool operator<=(const Rational_new& rat1, const Rational_new& rat2);
bool operator>(const Rational_new& rat1, const Rational_new& rat2);
bool operator>=(const Rational_new& rat1, const Rational_new& rat2);
bool operator==(const Rational_new& rat1, const Rational_new& rat2);
bool operator!=(const Rational_new& rat1, const Rational_new& rat2); // 重载+,-*/运算符,以非成员函数的方式
Rational_new operator+(const Rational_new& rat1, const Rational_new& rat2);
Rational_new operator-(const Rational_new& rat1, const Rational_new& rat2);
Rational_new operator*(const Rational_new& rat1, const Rational_new& rat2);
Rational_new operator/(const Rational_new& rat1, const Rational_new& rat2);#endif

rational_new.cpp文件

#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>#include "E:\back_up\code\c_plus_code\chapter14\external_file\rational_new.h"Rational_new::Rational_new()
{numerator = 0;denominator = 1;
}Rational_new::Rational_new(int numerator, int denominator)
{int gcd_value = gcd(numerator, denominator);this->numerator = ((denominator>0)?1:-1)*numerator/gcd_value;this->denominator = abs(denominator)/gcd_value;
}Rational_new::Rational_new(int n)  // 这个类的作用在于,当对象需要与整数进行某些运算操作的时候,Rational(int n)会将对象首先转换为Rational对象
{numerator = n;denominator = 1;
} int Rational_new::gcd(int a, int b)
{// 求n1, n2的最大公约数int n1 = abs(a);int n2 = abs(b);int tmp = (n1<n2)?n1:n2;while(tmp>1){if(a%tmp==0 && b%tmp==0){break;}else{tmp--;}}return tmp;
}int Rational_new::get_numerator() const
{return numerator;
}int Rational_new::get_denominator() const
{return denominator;
}Rational_new Rational_new::add(const Rational_new& rat) const
{int rat_num = rat.get_numerator();  // 分子 int rat_den = rat.get_denominator();    // 分母 int result_num = numerator*rat_den + denominator*rat_num;int result_den = denominator*rat_den;// int gcd_value = gcd(result_num, result_den);return Rational_new(result_num, result_den);
}
Rational_new Rational_new::subtract(const Rational_new& rat) const
{int rat_num = rat.get_numerator();  // 分子 int rat_den = rat.get_denominator();    // 分母 int result_num = numerator*rat_den - denominator*rat_num;int result_den = denominator*rat_den;// int gcd_value = gcd(result_num, result_den);return Rational_new(result_num, result_den);
}Rational_new Rational_new::multiply(const Rational_new& rat) const
{int rat_num = rat.get_numerator();  // 分子 int rat_den = rat.get_denominator();    // 分母 int result_num = numerator*rat_num;int result_den = denominator*rat_den;// int gcd_value = gcd(result_num, result_den);return Rational_new(result_num, result_den);
}Rational_new Rational_new::divide(const Rational_new& rat) const
{int rat_num = rat.get_numerator();  // 分子 int rat_den = rat.get_denominator();    // 分母 int result_num = numerator*rat_den;int result_den = denominator*rat_num;// int gcd_value = gcd(result_num, result_den);return Rational_new(result_num, result_den);
}int Rational_new::compareTo(const Rational_new& rat) const
{// compareTo()函数定义为const,所以不能对数据域进行修改,必须复制一个临时的值 Rational_new tmp(numerator, denominator);//Rational_new temp = subtract(rat);Rational_new temp = tmp.subtract(rat);/*if(temp.numerator>0) return 1;else if(temp.numerator==0)return 0;elsereturn -1;*/return (temp.numerator>0)?1:(temp.numerator==0)?0:-1;
}bool Rational_new::equalTo(const Rational_new& rat)
{int temp=compareTo(rat);return (temp==0)?true:false;
}int Rational_new::get_intValue() const
{return numerator/denominator;
}double Rational_new::get_doubleValue() const
{return (1.0*numerator)/denominator;
}string Rational_new::get_string() const
{stringstream ss;ss << numerator;if(denominator>1){ss << "/" << denominator;}return ss.str();
}// 重载运算符+=, -=, *=, /=运算符,这些是左值运算符,且以成员函数的形式实现
Rational_new& Rational_new::operator+=(const Rational_new& rat)
{*this = add(rat);return *this;
}
Rational_new& Rational_new::operator-=(const Rational_new& rat)
{*this = subtract(rat);return *this;
}
Rational_new& Rational_new::operator*=(const Rational_new& rat)
{*this = multiply(rat);return *this;
}
Rational_new& Rational_new::operator/=(const Rational_new& rat)
{*this = divide(rat);return *this;
}// 重载[]运算符,同样也是左值运算符,且以成员函数的形式实现
int& Rational_new::operator[](int index)
{return (index==0)?numerator:denominator;
}//重载前缀加和前缀减运算符,即--a,--b, 无参函数
Rational_new& Rational_new::operator++()
{numerator += denominator;return *this;
}
Rational_new& Rational_new::operator--()
{numerator -= denominator;return *this;
}// 重载后缀加和后缀减,即a--,a++, 伪参数
Rational_new Rational_new::operator++(int dummy)
{Rational_new temp(numerator, denominator);// Rational_new temp = *this;numerator += denominator;return temp;
}
Rational_new Rational_new::operator--(int dummy)
{Rational_new temp(numerator, denominator);numerator -= denominator;return temp;
}// 重载+-运算符,正负,无参数
Rational_new Rational_new::operator+()
{return *this;//return Rational_new(numerator, denominator);
}
Rational_new Rational_new::operator-()
{return Rational_new(-numerator, denominator);
}// 以非成员函数的形式实现关系运算符及+,-,*,/的重载
bool operator<(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.compareTo(rat2)<0;
}
bool operator<=(const Rational_new& rat1, const Rational_new& rat2)
{//return (rat1.compareTo(rat2)<0 || rat1.compareTo(rat2)==0)?true:false;return rat1.compareTo(rat2)<=0;
}
bool operator>(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.compareTo(rat2)>0;
}
bool operator>=(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.compareTo(rat2)>=0;
}
bool operator==(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.compareTo(rat2)==0;
}
bool operator!=(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.compareTo(rat2)!=0;
}// 重载+,-*/运算符,以非成员函数的方式
Rational_new operator+(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.add(rat2);
}
Rational_new operator-(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.subtract(rat2);
}
Rational_new operator*(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.multiply(rat2);
}
Rational_new operator/(const Rational_new& rat1, const Rational_new& rat2)
{return rat1.divide(rat2);
}

main.cpp文件

#include <iostream>
#include <cstdlib>
#include <string>
#include "E:\back_up\code\c_plus_code\chapter14\external_file\rational.h"
#include "E:\back_up\code\c_plus_code\chapter14\external_file\rational_new.h"using namespace std;
ostream& operator<<(ostream&, const Rational_new&);int main(int argc, char *argv[])
{   // 测试 Rational_new r1(6, 3);Rational_new r2(5, 9);// +-*/ cout << r1 << '+' << r2 << "=" << r1+r2 << endl;cout << r1 << '-' << r2 << "=" << r1-r2 << endl;cout << r1 << '*' << r2 << "=" << r1*r2 << endl;cout << r1 << '/' << r2 << "=" << r1/r2 << endl;// 通过非成员函数重载+,和定义Rational(int n)构造函数,实现+运算符的对称作用 cout << 5 << "+" << r1 << "=" << 5+r1 << endl;cout << r1 << "+" << 5 << "=" << r1+5 << endl;// 关系运算符测试:cout << r1 << ">" << r2 << " is " << ((r1>r2)?"true":"false") << endl;cout << r1 << ">=" << r2 << " is " << ((r1>=r2)?"true":"false") << endl;cout << r1 << "<" << r2 << " is " << ((r1<r2)?"true":"false") << endl;cout << r1 << "<=" << r2 << " is " << ((r1<=r2)?"true":"false") << endl;// +=运算符Rational_new r3(1,3);r3 += r1;cout << r3 << endl;r3[0]=3;r3[1]=10;cout << r3 << endl;Rational_new r4 = r3++;cout << r4 << endl;cout << r3 << endl;cout << ++r3 << endl;return 0;
}// 友元函数operator<< 的实现
ostream& operator<<(ostream& out, const Rational_new& rat)
{out << rat.numerator << "/" << rat.denominator;return out;
} 

--------------------------------------------------------end-----------------------------------------------

C++学习笔记(11) 重载流插入运算符和流提取运算符,以及自动类型转换相关推荐

  1. 算法学习笔记:网络流#4——ISAP 求解最大流

    算法学习笔记:网络流#4--ISAP 求解最大流 1. 前言 2. 模板 2.1 详解 2.2 正确性证明 2.3 代码 3. 算法对比 3.1 一般数据下的对比 3.2 特殊数据下的对比 4. 总结 ...

  2. SpringMVC:学习笔记(11)——依赖注入与@Autowired

    SpringMVC:学习笔记(11)--依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...

  3. JavaScript学习笔记01【基础——简介、基础语法、运算符、特殊语法、流程控制语句】

    w3school 在线教程:https://www.w3school.com.cn JavaScript学习笔记01[基础--简介.基础语法.运算符.特殊语法.流程控制语句][day01] JavaS ...

  4. Hadoop学习笔记—11.MapReduce中的排序和分组

    Hadoop学习笔记-11.MapReduce中的排序和分组 一.写在之前的 1.1 回顾Map阶段四大步骤 首先,我们回顾一下在MapReduce中,排序和分组在哪里被执行: 从上图中可以清楚地看出 ...

  5. HALCON 20.11:深度学习笔记(11)---目标检测

    HALCON 20.11:深度学习笔记(11)---目标检测 HALCON 20.11.0.0中,实现了深度学习方法. 本章讲解了如何使用基于深度学习的对象检测. 通过对象检测,我们希望在图像中找到不 ...

  6. 台大李宏毅Machine Learning 2017Fall学习笔记 (11)Convolutional Neural Network

    台大李宏毅Machine Learning 2017Fall学习笔记 (11)Convolutional Neural Network 本博客主要整理自: http://blog.csdn.net/x ...

  7. 华为HCIA-datacom 学习笔记11——AAA原理与配置

    华为HCIA-datacom 学习笔记11--AAA原理与配置 AAA原理与配置 1.AAA概述 认证(authentication):验证用户是否获得访问权,确定哪些用户可以访问网络 授权(auth ...

  8. 点云学习笔记11——VoxelNet算法+代码运行

    点云学习笔记11--VoxelNet算法+代码运行 一.算法分析 摘要 介绍 相关工作 1.2. 贡献 2.VoxelNet 2.1.特征学习网络 2.1.1 特征学习网络 二.代码复现 2.1.环境 ...

  9. 凸优化学习笔记 11:对偶原理 拉格朗日函数

    前面讲了凸优化问题的定义,以及一些常见的凸优化问题类型,这一章就要引入著名的拉格朗日函数和对偶问题了.通过对偶问题,我们可以将一些非凸问题转化为凸优化问题,还可以求出原问题的非平凡下界,这对复杂优化问 ...

最新文章

  1. sentinel限流_微服务架构进阶:Sentinel实现服务限流、熔断与降级
  2. CSS在ASP.NET中使用
  3. VS 2012 如何发布 ASP.NET 网站到本地IIS
  4. 超详细的CentOS7中安装Git,yum安装和自己编译安装
  5. DB2sql——DB2临时表的创建
  6. TTS Text-to-speech(文字转语音)服务
  7. windows下共享文件夹在Linux下打开
  8. 原来js的parseInt函数还可以这样用
  9. 微服务feignclient_搞微服务用阿里开源的 Nacos 真香啊
  10. oracle定时向mysql取数据_Oracle中通过Job实现定时同步两个数据表之间的数据
  11. safari里的touch事件解析
  12. 使用python抓取分析链家网二手房数据
  13. 面试Vue架构师,封装一个万能表单生成器
  14. TTMS剧院票务管理系统全网最全!!!不接受反驳
  15. 最新国产电源厂家及具体型号pin-to-pin替代手册发布
  16. windows11 mars xlog解密环境配置
  17. 学生护眼台灯aa和a的区别?分享适合学生的护眼台灯
  18. python提取Excel某几列数据
  19. EAS Web:新增按钮弹出新页签
  20. OCM Examination Guide

热门文章

  1. 微服务架构工作笔记003---了解认识google Kubernetes 容器管理
  2. jsp,servlet交互驱动层实现
  3. 杭电1861 游船出租
  4. poj2406Power string
  5. c++ assert() 使用方法
  6. Visual C++中动态链接库技术浅谈
  7. 现在2019年读职高学计算机好吗,读职高有用吗 学什么专业有发展
  8. python perl shell_Shell Perl Python 介绍
  9. python class用法理解_带你全面理解python中self的用法
  10. insert exec 语句不能嵌套_MySQL ------ 插入数据(INSERT和insert select)(二十)