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-----------------------------------------------
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 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)