C++学习笔记(11) 重载流插入运算符和流提取运算符,以及自动类型转换
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) 重载流插入运算符和流提取运算符,以及自动类型转换相关推荐
- 算法学习笔记:网络流#4——ISAP 求解最大流
算法学习笔记:网络流#4--ISAP 求解最大流 1. 前言 2. 模板 2.1 详解 2.2 正确性证明 2.3 代码 3. 算法对比 3.1 一般数据下的对比 3.2 特殊数据下的对比 4. 总结 ...
- SpringMVC:学习笔记(11)——依赖注入与@Autowired
SpringMVC:学习笔记(11)--依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...
- JavaScript学习笔记01【基础——简介、基础语法、运算符、特殊语法、流程控制语句】
w3school 在线教程:https://www.w3school.com.cn JavaScript学习笔记01[基础--简介.基础语法.运算符.特殊语法.流程控制语句][day01] JavaS ...
- Hadoop学习笔记—11.MapReduce中的排序和分组
Hadoop学习笔记-11.MapReduce中的排序和分组 一.写在之前的 1.1 回顾Map阶段四大步骤 首先,我们回顾一下在MapReduce中,排序和分组在哪里被执行: 从上图中可以清楚地看出 ...
- HALCON 20.11:深度学习笔记(11)---目标检测
HALCON 20.11:深度学习笔记(11)---目标检测 HALCON 20.11.0.0中,实现了深度学习方法. 本章讲解了如何使用基于深度学习的对象检测. 通过对象检测,我们希望在图像中找到不 ...
- 台大李宏毅Machine Learning 2017Fall学习笔记 (11)Convolutional Neural Network
台大李宏毅Machine Learning 2017Fall学习笔记 (11)Convolutional Neural Network 本博客主要整理自: http://blog.csdn.net/x ...
- 华为HCIA-datacom 学习笔记11——AAA原理与配置
华为HCIA-datacom 学习笔记11--AAA原理与配置 AAA原理与配置 1.AAA概述 认证(authentication):验证用户是否获得访问权,确定哪些用户可以访问网络 授权(auth ...
- 点云学习笔记11——VoxelNet算法+代码运行
点云学习笔记11--VoxelNet算法+代码运行 一.算法分析 摘要 介绍 相关工作 1.2. 贡献 2.VoxelNet 2.1.特征学习网络 2.1.1 特征学习网络 二.代码复现 2.1.环境 ...
- 凸优化学习笔记 11:对偶原理 拉格朗日函数
前面讲了凸优化问题的定义,以及一些常见的凸优化问题类型,这一章就要引入著名的拉格朗日函数和对偶问题了.通过对偶问题,我们可以将一些非凸问题转化为凸优化问题,还可以求出原问题的非平凡下界,这对复杂优化问 ...
最新文章
- sentinel限流_微服务架构进阶:Sentinel实现服务限流、熔断与降级
- CSS在ASP.NET中使用
- VS 2012 如何发布 ASP.NET 网站到本地IIS
- 超详细的CentOS7中安装Git,yum安装和自己编译安装
- DB2sql——DB2临时表的创建
- TTS Text-to-speech(文字转语音)服务
- windows下共享文件夹在Linux下打开
- 原来js的parseInt函数还可以这样用
- 微服务feignclient_搞微服务用阿里开源的 Nacos 真香啊
- oracle定时向mysql取数据_Oracle中通过Job实现定时同步两个数据表之间的数据
- safari里的touch事件解析
- 使用python抓取分析链家网二手房数据
- 面试Vue架构师,封装一个万能表单生成器
- TTMS剧院票务管理系统全网最全!!!不接受反驳
- 最新国产电源厂家及具体型号pin-to-pin替代手册发布
- windows11 mars xlog解密环境配置
- 学生护眼台灯aa和a的区别?分享适合学生的护眼台灯
- python提取Excel某几列数据
- EAS Web:新增按钮弹出新页签
- OCM Examination Guide
热门文章
- 微服务架构工作笔记003---了解认识google Kubernetes 容器管理
- jsp,servlet交互驱动层实现
- 杭电1861 游船出租
- poj2406Power string
- c++ assert() 使用方法
- Visual C++中动态链接库技术浅谈
- 现在2019年读职高学计算机好吗,读职高有用吗 学什么专业有发展
- python perl shell_Shell Perl Python 介绍
- python class用法理解_带你全面理解python中self的用法
- insert exec 语句不能嵌套_MySQL ------ 插入数据(INSERT和insert select)(二十)