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文件:

扫描二维码关注公众号,回复: 4903135 查看本文章
// 自动类型转换
// 定义运算符函数 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-----------------------------------------------

猜你喜欢

转载自blog.csdn.net/zj1131190425/article/details/84642833