Fraction.h头文件代码:
#pragma once
class Fraction {
private:
int p;
int q;
public:
Fraction(int, int); //构造函数声明
int gcd(int, int)const; //求最大公约数
void Output(); //打印
Fraction& operator++();
//前自增运算符重载,返回Fraction类引用
Fraction operator++(int);
//后自增运算符重载,返回一个Fraction类对象。规定参数里必须加上int型。实际上并不起作用
friend Fraction operator+(const Fraction& , const Fraction&);
//全局友元加法运算符重载函数。
//常引用(const Fraction&)是因为只需要对对象进行计算,不需要改变原对象的数据
friend Fraction operator-(const Fraction&, const Fraction&);
//全局友元减法运算符重载函数
friend Fraction operator*(const Fraction&, const Fraction&);
//全局友元乘法运算符重载函数
friend Fraction operator/(const Fraction&, const Fraction&);
//全局友元除法运算符重载函数
};
下面是类的实现:(均放在main.cpp里,即声明和定义分开)
gcd(greatest common divisor)函数实现:
用到了辗转相除法。可以参考辗转相除法 - unique_ptr - 博客园 (cnblogs.com)
int Fraction::gcd(int a, int b)const
{ //辗转相除法,返回最大公约数
int r;
while (b) {
r = b;
b = a % b;
a = r;
}
return (a == 0 ? 1 : a);
}
构造函数实现
Fraction::Fraction(int m, int n) {
int g = gcd(m, n);
p = m / g; //同时除以最大公约数
q = n / g;
}
后自增(x++)运算符重载:
Fraction Fraction::operator++(int) { //后自增
Fraction temp(*this); //用默认拷贝构造函数,把当前对象保存在temp里
p++;
int g = gcd(p, q);
p /= g;
q /= g;
return temp;
}
前自增(++x)运算符重载:
Fraction& Fraction::operator++() { //前自增
p++;
int g = gcd(p, q);
p /= g;
q /= g;
return *this; //返回当前对象的引用
}
注意:
最重要的一点:前自增和后自增都是以“①类内定义非静态的成员函数”形式出现,而且参数列表为空,是因为成员函数自带一个this指针,这是隐性存在的。相当于我们有一个隐性的参数。
而我们下面要介绍的加减乘除的运算符重载都是以"②类外定义全局函数、类内声明成友元函数"形式出现,一般我们规定运算具有对称性的运算符往往采取②。实际上,无论是自增还是四则运算,都可以采用另外一种形式写。具体操作方法请读者自行思考,笔者受限于篇幅不赘述。
+运算符重载:
Fraction operator+(const Fraction& F1, const Fraction& F2) {
Fraction temp(0, 0);
temp.q = F1.q * F2.q;
temp.p = F1.q * F2.p + F2.q * F1.p;
int g = temp.gcd(temp.p, temp.q);
temp.p /= g;
temp.q /= g;
return temp;
}
-运算符重载:
Fraction operator-(const Fraction& F1, const Fraction& F2) {
Fraction temp(F2);
temp.p *= -1; //temp取F2的负数
return (F1 + temp); //复用了对+的重载,减少代码量
}
下面附上main.cpp的完整代码:
#include<iostream>
#include"Fraction.h"
using namespace std;
int main() {
srand((unsigned)time(NULL)); //随机数生成数据
Fraction f1(rand() % 3 + 1, rand() %4 + 2);
Fraction f2(rand() % 3 + 1, rand() %4 + 2);
Fraction f3=f1+f2;
Fraction f4 = f1 - f2;
Fraction f5= f1 * f2;
Fraction f6 = f1 / f2;
f1.Output();
f2.Output();
f3.Output();
f4.Output();
f5.Output();
f6.Output();
}
//Fraction类的实现:
Fraction::Fraction(int m, int n) {
int g = gcd(m, n);
p = m / g; //同时除以最大公约数
q = n / g;
}
int Fraction::gcd(int a, int b)const
{ //辗转相除法,返回最大公约数
int r;
while (b) {
r = b;
b = a % b;
a = r;
}
return (a == 0 ? 1 : a);
}
void Fraction::Output() {
cout << p << "/" << q<<endl;
}
Fraction& Fraction::operator++() { //前自增
p++;
int g = gcd(p, q);
p /= g;
q /= g;
return *this; //返回当前对象的引用
}
Fraction Fraction::operator++(int) { //后自增
Fraction temp(*this); //用默认拷贝构造函数,把当前对象保存在temp里
p++;
int g = gcd(p, q);
p /= g;
q /= g;
return temp;
}
Fraction operator+(const Fraction& F1, const Fraction& F2) {
Fraction temp(0, 0);
temp.q = F1.q * F2.q;
temp.p = F1.q * F2.p + F2.q * F1.p;
int g = temp.gcd(temp.p, temp.q);
temp.p /= g;
temp.q /= g;
return temp;
}
Fraction operator-(const Fraction& F1, const Fraction& F2) {
Fraction temp(F2);
temp.p *= -1; //temp取F2的负数
return (F1 + temp); //复用了对+的重载,减少代码量
}
Fraction operator*(const Fraction& F1, const Fraction& F2) {
Fraction temp(1, 1);
temp.p = F1.p * F2.p;
temp.q = F1.q * F2.q;
int g = temp.gcd(temp.p, temp.q);
temp.p /= g;
temp.q /= g;
return temp;
}
Fraction operator/(const Fraction& F1, const Fraction& F2) {
Fraction temp(F2);
int t = temp.p;
temp.p = temp.q;
temp.q = t; //颠倒F2的分子分母用来
return F1 * temp; //复用*运算符重载,减少代码量
}
文件结构如下:
尾声:
介绍一个小技巧!VS编译环境下,Ctrl+ M+O可以一键折叠所有的代码块。Ctrl+M+L可以一键打开所有的代码块。这个快捷键在代码维护的时候非常的贴心。
最后附上运算符重载表:
其中,=、[ ]、( )、->这四个必须是非静态成员函数方式的重载。