[分享] 建立一個分數類別 ( class Rational )
目標:
建立一個分數類別,運作方式跟內建的 + 運算子相同。
設計:
1. 用兩個泛型整數代表分子分母,分母 > 0
2. 運用 const 修飾詞達成語意 eq. (r1+r2) = r3 //Compile Error
3. 能跟整數一起運作 eq. r1 = 1; r1= r2+1;
4. 自訂 operator << 使得分數可以被 ostream 輸出
使用案例:
Rational <long long> r0;
Rational <long long> r1 = 1;
Rational <long long> r2 = r1 + 1;
(r1 + r2) = r0; //compile error!!
r1+=r2;
r1 + = 1;
r1 = 1 + r2;
cout << r1 << r2;
參考:
都是參考 Scott Meyers 的 Effective C++(3/e) & More Effective C++
這個 Rational 案例被分散到各個條款,我整理成一個完整的 class
Effective C++ (3/e) (E)
條款 3: Use const whenever possible // constraint (r1+r2)=r0
條款24: Declare non-member function when type conversions should apply to
all parameters. // enable r1 = 1 + r2;
條款46: Define non-member functions inside templates when type conversions
are desired. // Rational<long long>
More Effective C++ (ME)
條款20: Facilitate the return value optimization //Implementation detail
條款22: Consider using op= instead of stand-alone op // impl detail
程式碼
======================= Rational.h =======================
#pragma once
#include <ostream>
#include <cassert>
template <class T>
class Rational
{
//friend 在 template 的涵義是為了要能具現化
//並不只為了存取 private 參考 E46
friend std::ostream& operator<<(std::ostream& os,const Rational& r)
{
if(r.d_ == 1)
os << r.d_;
else
os << r.n_ << "/" << r.d_;
return os;
}
friend bool operator==(const Rational& lhs,const Rational& rhs)
{
return (lhs.d_ == rhs.d_) && (lhs.n_==rhs.n_);
}
//參考 E3 防止 (r1+r2) 被賦值
friend const Rational operator+(const Rational& lhs,const Rational& rhs)
{
return Rational(lhs)+=rhs; //RVO ME20
}
friend const Rational operator*(const Rational& lhs,const Rational& rhs)
{
return Rational(lhs)*=rhs;
}
T n_; //numerator 分子
T d_; //denominator 分母
public:
Rational(T n = 0,T d = 1) : n_(n),d_(d){ assert(d_>0); reduce(); }
//參考 ME22
Rational& operator+=(const Rational& rhs){
T g = gcd(rhs.d_,d_);
T l = d_ * (rhs.d_/g); // lcm 最小公倍數
n_ = n_*(l/d_) + rhs.n_*(l/rhs.d_);
d_=l;
reduce();
return*this;
}
Rational& operator*=(const Rational& rhs){
d_*=rhs.d_;
n_*=rhs.n_;
reduce();
return*this;
}
private:
// 最大公因數
T gcd(T m,T n)
{
return n?gcd(n,m%n):m;
}
// 約分
void reduce()
{
T g = gcd(d_,n_);
if(g != 1){
d_/=g;
n_/=g;
}
}
};
====================================================
備註:
1. 這個類別示範了設計重載運算子該注意的事項
2. 加法和乘法的實作部分我就沒特別考慮效率eq. gcd 用遞迴實作
可以試試看如何把 lazy evaluation 實作進去
3. 減法、除法和比較運算子的介面可以依此類推
4. 正負號部分我目前把是用分子主導 (分母恆正),錯誤處理的部分沒實作上去
"Rational.h" 的實作碼 http://codepad.org/MT6qOUa9
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 220.134.96.34
→
12/30 13:35, , 1F
12/30 13:35, 1F
推
12/30 19:54, , 2F
12/30 19:54, 2F
→
12/30 19:56, , 3F
12/30 19:56, 3F
→
12/30 20:08, , 4F
12/30 20:08, 4F
→
12/30 20:10, , 5F
12/30 20:10, 5F
→
12/30 20:41, , 6F
12/30 20:41, 6F
→
12/30 20:42, , 7F
12/30 20:42, 7F
→
12/30 20:43, , 8F
12/30 20:43, 8F
→
12/30 21:02, , 9F
12/30 21:02, 9F
→
12/30 21:03, , 10F
12/30 21:03, 10F
→
12/30 21:04, , 11F
12/30 21:04, 11F
→
12/30 21:06, , 12F
12/30 21:06, 12F
→
12/30 21:08, , 13F
12/30 21:08, 13F
→
12/30 21:08, , 14F
12/30 21:08, 14F
→
12/30 21:21, , 15F
12/30 21:21, 15F
推
12/30 23:51, , 16F
12/30 23:51, 16F
→
12/30 23:52, , 17F
12/30 23:52, 17F
→
12/30 23:52, , 18F
12/30 23:52, 18F
→
12/30 23:52, , 19F
12/30 23:52, 19F
→
12/30 23:53, , 20F
12/30 23:53, 20F
→
12/30 23:53, , 21F
12/30 23:53, 21F
→
12/30 23:57, , 22F
12/30 23:57, 22F
→
12/30 23:58, , 23F
12/30 23:58, 23F
→
12/30 23:59, , 24F
12/30 23:59, 24F
→
12/31 00:00, , 25F
12/31 00:00, 25F
推
12/31 00:22, , 26F
12/31 00:22, 26F
→
12/31 00:23, , 27F
12/31 00:23, 27F
→
12/31 00:24, , 28F
12/31 00:24, 28F
→
12/31 00:25, , 29F
12/31 00:25, 29F
→
12/31 00:31, , 30F
12/31 00:31, 30F
→
12/31 00:31, , 31F
12/31 00:31, 31F
→
12/31 08:48, , 32F
12/31 08:48, 32F
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章