C++有理數類設計
C++有理數類設計
有理數類主要功能設計
之前用C語言設計了有理數資料型別C語言實現有理數資料型別(有理數庫),這裡再用C++做個有理數類。有理數類的功能就比C語言的有理數資料型別功能強多了,主要就是運算子過載。
- 有理數類,能實現以m/n形式的輸入輸出,支援加減乘除運算;
- 支援加賦,減賦,乘賦,除賦,判等,大於,小於運算;
- 也支援和普通double型別混合進行以上這些運算;
- 運算結果均已化簡;
- 注意由於內部分子分母均是int型,乘除法容易溢位。
- 設計除法的除數為0時,會報錯退出。
以下是有理數類標頭檔案rational_oop.h:
#ifndef RATIONAL_H
#define RATIONAL_H
#include <iostream>
using namespace std;
class Rational
{
private:
int fenzi, fenmu;
void simply();//化簡
bool negative() const;//判斷是否是負數
public:
Rational(int numerator = 0, int denominator = 1);//建構函式
Rational(const double n);//型別轉換建構函式
Rational(const Rational & ra);//複製建構函式
//~Rational();沒有動態分配,預設析構就行
Rational & operator =(const Rational & ra);
Rational & operator =(const double & n);//使有理數類物件能被double型別賦值
//以下20個函式使有理數類物件能和double型別混合加減乘除和賦值
Rational operator +(const Rational & ra);
Rational operator -(const Rational & ra);
Rational operator *(const Rational & ra);
Rational operator /(const Rational & ra);
Rational operator +(const double & n);
Rational operator -(const double & n);
Rational operator *(const double & n);
Rational operator /(const double & n);
friend Rational operator +(const double & n, const Rational & ra);
friend Rational operator -(const double & n, const Rational & ra);
friend Rational operator *(const double & n, const Rational & ra);
friend Rational operator /(const double & n, const Rational & ra);
Rational & operator +=(const Rational & ra);
Rational & operator -=(const Rational & ra);
Rational & operator *=(const Rational & ra);
Rational & operator /=(const Rational & ra);
Rational & operator +=(const double & n);
Rational & operator -=(const double & n);
Rational & operator *=(const double & n);
Rational & operator /=(const double & n);
int GetFenzi() { return fenzi; }
int GetFenmu() { return fenmu; }
void Set(int numerator, int denominator) { fenzi = numerator; fenmu = denominator; }
//過載強制型別轉換運算子,使得凡是應該出現double型的地方,均可以由有理數類物件替代。比如,可以使得
//有理數類物件和普通double型比較大小成為可能
operator double();
//支援以m/n形式的有理數類物件輸入輸出,負號會顯示在前面。
friend ostream & operator <<(ostream & os, const Rational & ra);
friend istream & operator >>(istream & is, Rational & ra);
};
#endif
rational_oop.cpp
#include <iostream>
#include <string>
#include <cstdlib>
#include "rational_oop.h"
using namespace std;
void Rational::simply()//輾轉相除法求最大公約數化簡
{
int a = fenzi, b = fenmu;
while (b){
int mod = a % b;
a = b;
b = mod;
}
fenzi /= a;
fenmu /= a;
}
bool Rational::negative() const
{
return (fenzi < 0 || fenmu < 0);
}
Rational::Rational(int numerator, int denominator)
{
fenzi = numerator;
fenmu = denominator;
simply();//確保任意路徑得到的有理數類物件均是最簡形式
}
Rational::Rational(const double n)
{
double numerator = n, denominator = 1;
while ((int)numerator != numerator) {
numerator *= 10;
denominator *= 10;
}
fenzi = numerator, fenmu = denominator;
simply();//確保任意路徑得到的有理數類物件均是最簡形式
}
Rational::Rational(const Rational & ra): fenzi(ra.fenzi), fenmu(ra.fenmu) {}
Rational & Rational::operator =(const Rational & ra)
{
fenzi = ra.fenzi, fenmu = ra.fenmu;
return *this;
}
Rational & Rational::operator =(const double & n)
{
Rational tmp(n);
*this = tmp;
return *this;
}
Rational Rational::operator +(const Rational & ra)
{
int numerator = fenzi * ra.fenmu + ra.fenzi * fenmu;
int denominator = fenmu * ra.fenmu;
return Rational(numerator, denominator);
}
Rational Rational::operator -(const Rational & ra)
{
int numerator = fenzi * ra.fenmu - ra.fenzi * fenmu;
int denominator = fenmu * ra.fenmu;
return Rational(numerator, denominator);
}
Rational Rational::operator *(const Rational & ra)
{
int numerator = fenzi * ra.fenzi;
int denominator = fenmu * ra.fenmu;
return Rational(numerator, denominator);
}
Rational Rational::operator /(const Rational & ra)
{
if (ra.fenzi == 0) {
cout << "除數為0了!" << endl;
exit(1);
}
int numerator = fenzi * ra.fenmu;
int denominator = fenmu * ra.fenzi;
return Rational(numerator, denominator);
}
Rational Rational::operator +(const double & n)
{
Rational tmp(n);
return *this + tmp;
}
Rational Rational::operator -(const double & n)
{
Rational tmp(n);
return *this - tmp;
}
Rational Rational::operator *(const double & n)
{
Rational tmp(n);
return *this * tmp;
}
Rational Rational::operator /(const double & n)
{
Rational tmp(n);
return *this / tmp;
}
Rational operator +(const double & n, const Rational & ra)
{
Rational tmp(n);
return tmp + ra;
}
Rational operator -(const double & n, const Rational & ra)
{
Rational tmp(n);
return tmp - ra;
}
Rational operator *(const double & n, const Rational & ra)
{
Rational tmp(n);
return tmp * ra;
}
Rational operator /(const double & n, const Rational & ra)
{
Rational tmp(n);
return tmp / ra;
}
Rational & Rational::operator +=(const Rational & ra)
{
Rational tmp = *this + ra;
*this = tmp;
return *this;
}
Rational & Rational::operator -=(const Rational & ra)
{
Rational tmp = *this - ra;
*this = tmp;
return *this;
}
Rational & Rational::operator *=(const Rational & ra)
{
Rational tmp = *this * ra;
*this = tmp;
return *this;
}
Rational & Rational::operator /=(const Rational & ra)
{
Rational tmp = *this / ra;
*this = tmp;
return *this;
}
Rational & Rational::operator +=(const double & ra)
{
Rational tmp(ra);
*this += tmp;
return *this;
}
Rational & Rational::operator -=(const double & ra)
{
Rational tmp(ra);
*this -= tmp;
return *this;
}
Rational & Rational::operator *=(const double & ra)
{
Rational tmp(ra);
*this *= tmp;
return *this;
}
Rational & Rational::operator /=(const double & ra)
{
Rational tmp(ra);
*this /= tmp;
return *this;
}
Rational::operator double()
{
return (double) fenzi / fenmu;
}
ostream & operator <<(ostream & os, const Rational & ra)
{
if (ra.fenzi == 0)
os << 0;
else if (ra.negative())
os << "-" << abs(ra.fenzi) << "/" << abs(ra.fenmu); //如果是負數,符號寫在前面。
else
os << ra.fenzi << "/" << ra.fenmu;
return os;
}
istream & operator >>(istream & is, Rational & ra)
{
string s;
is >> s;
int pos = s.find("/", 0);
string sTmp = s.substr(0, pos);
ra.fenzi = atoi(sTmp.c_str());//讀入分子
sTmp = s.substr(pos+1, s.length() - pos - 1);
ra.fenmu = atoi(sTmp.c_str());//讀入分母
return is;
}
測試程式和程式執行結果
GCC編譯的。
main.cpp
#include <iostream>
#include "rational_oop.h"
using namespace std;
int main(void)
{
cout << "該程式用來測試有理數類:" << endl;
cout << "由於內部用int型裝分子分母,所以輸入的數不要太大,計算乘除容易溢位:" << endl << endl;
Rational ra1, ra2(8.8);
cout << "請以m/n的形式輸入一個有理數ra1:";
cin >> ra1;
Rational ra3 = ra1;
cout << "這裡還用8.8為引數構造了ra2,用ra1為引數初始化ra3.現在:" << endl;
cout << "ra1 = " << ra1 << " ra2 = " << ra2 << " ra3 = " << ra3 << ";" << endl << endl;
ra1 = ra2;
ra2 = 66.6;
cout << "這裡讓ra1 = ra2, ra2 = 66.6。"<< "現在:" << endl;
cout << "ra1 = " << ra1 << " ra2 = " << ra2 << " ra3 = " << ra3 << ";" << endl << endl;
cout << "ra2 + ra3 = " << (ra2 + ra3) << endl;
cout << "ra2 - ra3 = " << (ra2 - ra3) << endl;
cout << "ra2 * ra3 = " << (ra2 * ra3) << endl;
cout << "ra2 / ra3 = " << (ra2 / ra3) << endl << endl;
cout << "ra2 + 34.55 = " << (ra2 + 34.55) << endl;
cout << "ra2 - 7.9 = " << (ra2 - 7.9) << endl;
cout << "ra2 * 3.6 = " << (ra2 * 3.6) << endl;
cout << "ra2 / 2.5 = " << (ra2 / 2.5) << endl << endl;
cout << "5.0 + ra2 = " << (5.0 + ra2) << endl;
cout << "88.88 - ra2 = " << (88.88 - ra2) << endl;
cout << "5.6 * ra2 = " << (5.6 * ra2) << endl;
cout << "102.4 / ra2 = " << (102.4 / ra2) << endl << endl;
cout << "現在" ;
cout << "ra1 = " << ra1 << " ra2 = " << ra2 << " ra3 = " << ra3 << ";" << endl << endl;
ra2 += 6.0;
cout << "ra2 += 6.0, ra2 = " << ra2 << endl;
ra2 -= 6.0;
cout << "ra2 -= 6.0, ra2 = " << ra2 << endl;
ra2 *= 6.0;
cout << "ra2 *= 6.0, ra2 = " << ra2 << endl;
ra2 /= 6.0;
cout << "ra2 /= 6.0, ra2 = " << ra2 << endl<< endl;
ra2 += ra3;
cout << "ra2 += ra3, ra2 = " << ra2 << endl;
ra2 -= ra3;
cout << "ra2 -= ra3, ra2 = " << ra2 << endl;
ra2 *= ra3;
cout << "ra2 *= ra3, ra2 = " << ra2 << endl;
ra2 /= ra3;
cout << "ra2 /= ra3, ra2 = " << ra2 << endl << endl;
cout << "現在" ;
cout << "ra1 = " << ra1 << " ra2 = " << ra2 << " ra3 = " << ra3 << ";" << endl << endl;
cout << "我現在double出一個變數n。賦初值為9.1;" << endl;
double n = 9.1;
n += ra2;
cout << "n += ra2, n = " << n << endl;
n -= ra2;
cout << "n -= ra2, n = " << n << endl;
n *= ra2;
cout << "n *= ra2, n = " << n << endl;
n /= ra2;
cout << "n /= ra2, n = " << n << endl << endl;
cout << "現在" ;
cout << "ra1 = " << ra1 << " ra2 = " << ra2 << " ra3 = " << ra3 << ";" << endl << endl;
cout << "ra1 > ra2, 結果為" << (ra1 > ra2) << endl;
cout << "ra1 != ra2, 結果為" << (ra1 != ra2) << endl;
cout << "ra1 == ra1, 結果為" << (ra1 == ra1) << endl;
cout << "ra1 > 8, 結果為" << (ra1 > 8) << endl;
cout << "88 > ra2, 結果為" << (88 > ra2) << endl;
cout << "8.8 == ra1, 結果為" << (8.8 == ra1) << endl;
return 0;
}
執行示例結果:
一點小問題
我也看了網上別人寫的,我覺得我這個才是比較夠大夠完整的。有人把 判等 ,!=, >, <這些全都過載了,其實沒必要,甚至連+ - ×÷我感覺也沒必要。關鍵是過載強制型別轉換運算子(double)。(operator double(); 成員函式)
有了對double運算子的過載,本該出現double型別的變數或常數的地方,如果出現了一個Rational有理數類物件,那麼該物件上的operator double()成員函式就會被呼叫,然後取其返回值使用。比如“<”號兩旁的運算元如果是double型別的變數或常量的話,就能解釋得通,而因為過載了double運算子,有理數類物件就可以替換掉這兩個運算元。按理說+ - ×÷這些運算也應如此。所以可以省略好多運算子過載函式。但我實際測試了一下:
把所有運算子過載全都註釋掉,只留強制型別轉換運算子過載的情況下,同樣在main.cpp裡輸入3/4的資料。會發現可以執行,結果也正確,只是結果都用小數來表示的:
我們希望結果是用有理數來表示的,所以過載+ - ×÷,加賦,減賦等還是有必要的,但判等之類的運算結果是真或假,就沒必要過載了。
我突發奇想如果用(Rational)強制型別轉換把小數運算結果轉成有理數分數結果行不行,發現:
cout << "ra2 + ra3 = " << (Rational)(ra2 + ra3) << endl; //執行顯示ra2 + ra3 = 1347/20, 正確
cout << "ra2 * ra3 = " << (Rational)(ra2 * ra3) << endl; //程式卡住了
其他四則運算也有問題,用(Rational)強制型別轉換不一定管用。不知道什麼原因,沒深究。
相關文章
- 【演算法學習】數學專題 有理數類别範本演算法
- 基礎程式設計題(PTA) 7-35 有理數均值 (20分)程式設計
- Google C++程式設計風格指南(三):C++ 類GoC++程式設計
- java實現有理數分數相關計算(淺度拷貝)案例Java
- Google C++ 程式設計風格指南:類GoC++程式設計
- 程式設計師單身真的是有理由的嗎?程式設計師
- 有理想的程式設計師必須知道的15件事程式設計師
- 【C++】從設計原理來看string類C++
- C++中的連結串列類的設計C++
- C++基礎::類設計的幾大原則C++
- C++的函數語言程式設計C++函數程式設計
- C++程式設計基礎(2)變數C++程式設計變數
- Effective C++:類與函式的設計和申明C++函式
- 《C++ API 設計》——寫給想寫好類庫的程式設計師C++API程式設計師
- C++ 大整數類(BigInteger類)實現C++
- (C++模板程式設計):通過遞迴組合、tuple及基類引數包展開引數包C++程式設計遞迴
- 【c++】引用計數C++
- 計數類 DP
- 一個隨機數的類c++隨機C++
- C++預設引數C++
- C/C++程式設計知識:C++ 快速隨機數生成器C++程式設計隨機
- C++程式設計C++程式設計
- C++ 簡單實現陣列類泛型程式設計示例C++陣列泛型程式設計
- Python程式設計:Counter計數器-dict字典的子類Python程式設計
- visual C++數字影像處理類C++
- [C++]C++程式設計例項C++程式設計
- C++ 統計單詞數C++
- 用 C++ 實現類似於 JAVA HttpServlet 的程式設計介面C++JavaHTTPServlet程式設計
- C++併發程式設計框架Theron(7)——Theron中包含的類(一)C++程式設計框架
- C++併發程式設計框架Theron(8)——Theron中包含的類(二)C++程式設計框架
- C++之數字計數演算法C++演算法
- C++抽象設計目的C++抽象
- 《C++程式設計教程》C++程式設計
- C++核心程式設計C++程式設計
- 用託管類庫的方式在C#中使用C++編寫的類(設計流程)C#C++
- 統計位數為偶數的數字(C++)C++
- 淺談C++物理設計:設計原則C++
- 【設計模式】設計模式的分類設計模式