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;
else
return -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-----------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @   Alpha205  阅读(311)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示