承接上集,本文為日期類別加入關係運算子、減法運算子、輸入輸出流支援、友元函數、靜態成員與預設建構函數取得當前日期,展示 C++ 進階特性的綜合運用。
新增 compare(const Date&) 回傳負/零/正,類似 strcmp,可直接用於 qsort 比較函數。並以此實作六個關係運算子:
int compare(const Date& d2) const; // 成員函數
int operator<(const Date& d2) const { return compare(d2) < 0; }
int operator<=(const Date& d2) const { return compare(d2) ≤ 0; }
int operator>(const Date& d2) const { return compare(d2) > 0; }
int operator>=(const Date& d2) const { return compare(d2) ≥ 0; }
int operator==(const Date& d2) const { return compare(d2) == 0; }
int operator!=(const Date& d2) const { return compare(d2) != 0; }
編譯器將 d1 < d2 轉為 d1.operator<(d2),語法自然直觀。
原 interval 函數功能即減法,重命名為 operator- 更符合直覺。回傳 Date 物件表示差值(年、月、日),並支援一元負號:
Date operator-(const Date& d2) const; // 二元減法
Date operator-() const; // 一元負號
約定:正日期所有資料成員為正,負日期反之,不允許符號混合。實作中為每個成員套用正確正負號並重新建構物件。
為讓 Date 擁有內建型別般的 I/O 體驗,需定義全域友元函數(因 stream 在左運算元):
// 類別宣告中
friend ostream& operator<<(ostream& os, const Date& d);
friend istream& operator>>(istream& is, Date& d);
// 實作
ostream& operator<<(ostream& os, const Date& d) {
os << d.get_month() << '/' << d.get_day() << '/' << d.get_year();
return os;
}
istream& operator>>(istream& is, Date& d) {
int m, day, y; char c;
is >> m >> c >> day >> c >> y;
d = Date(m, day, y); // 利用建構函數驗證合法性
return is;
}
宣告為 friend 可直接存取私有成員,提升效率(雖此處透過存取器亦可)。
dtab[])。this 指標,可透過類別名直接呼叫 Date::isleap(y),不需物件實例。class Date {
static int dtab[2][13]; // 靜態資料成員
static bool isleap(int y); // 靜態成員函數
public:
static bool IsLeapYear(int y) { return isleap(y); } // 公開介面
};
重新定義無參數建構函數,呼叫 C 執行期函數取得系統時間並初始化:
Date::Date() {
time_t t = time(NULL);
struct tm *now = localtime(&t);
month = now->tm_mon + 1;
day = now->tm_mday;
year = now->tm_year + 1900;
}
透過建構函數自動初始化、private 保護資料、運算子多載提供自然語法、I/O 浴流整合、靜態成員共享邏輯,這個 Date 類別已具備使用者定義型別應有的完整外觀與行為。C++ 的資料抽象機制讓我們能創造出如同內建型別般直觀、安全、可維護的抽象實體。