2017年11月05日
《その106》 静的データメンバ,静的メンバ関数,演算子関数(p.473演習13-1)
次のプログラムは、新版明解C++入門編 p.469 〜 p.472 にある日付に関するプログラムです。
静的データメンバ static int dmax[];
静的メンバ関数 static int days_of_month(int y, int m);
static bool leap_year(int year)
は、特定のオブジェクトではなくクラス全体に関わるデータ(各月の日数)または作業(各月の日数を調べる、閏年かどうかを調べる)です。
このようなデータや作業は、静的データメンバ・静的メンバ関数で実現するべきです。
------------------------------------------------
// Date.h
#ifndef ___Class_Date
#define ___Class_Date
#include <string>
#include <iostream>
class Date {
int y; // 西暦年
int m; // 月
int d; // 日
static int dmax[]; // 各月の日数(静的データメンバ)
static int days_of_month(int y, int m); // y年m月の日数(静的メンバ関数)
public:
Date(); // デフォルトコンストラクタ
Date(int yy, int mm = 1, int dd = 1); // コンストラクタ
static bool leap_year(int year) { // 閏年なら true を返却(静的メンバ関数)
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
int year() const { return y; } // 年を返却
int month() const { return m; } // 月を返却
int day() const { return d; } // 日を返却
bool leap_year() const { // 閏年なら true を返却(非静的メンバ関数)
return leap_year(y);
}
Date preceding_day() const; // 前日の日付を返却
Date following_day() const; // 翌日の日付を返却
int day_of_year() const; // 年内の経過日数を返却
int day_of_week() const; // 曜日を返却
std::string to_string() const; // 文字列表現を返却
};
std::ostream& operator<<(std::ostream& s, const Date& x); // 挿入子の多重定義
#endif
// Date.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <ctime>
#include <sstream>
#include <iostream>
#include "Date.h"
using namespace std;
// 各月の日数(閏年でない年)
int Date::dmax[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// y年m月の日数
int Date::days_of_month(int y, int m) {
return dmax[m - 1] + (leap_year(y) && m == 2);
}
// デフォルトコンストラクタ(今日の日付で作成)
Date::Date() {
time_t current = time(NULL); // 現在の暦時刻を取得
struct tm* local = localtime(&current); // 要素別の時刻に変換
y = local->tm_year + 1900; // 年:tm_yearは西暦年-1900
m = local->tm_mon + 1; // 月:tm_monは0〜11
d = local->tm_mday;
}
// コンストラクタ(指定した年月日で作成)
Date::Date(int yy, int mm, int dd) {
y = yy;
m = mm;
d = dd;
}
// 年内の経過日数
int Date::day_of_year() const {
int days = d;
for (int i = 1; i < m; i++)
days += days_of_month(y, i);
return days;
}
// 前日の日付
Date Date::preceding_day() const {
Date temp = *this;
if (temp.d > 1)
temp.d--;
else {
if (--temp.m < 1) {
temp.y--;
temp.m = 12;
}
temp.d = days_of_month(temp.y, temp.m);
}
return temp;
}
// 翌日の日付
Date Date::following_day() const {
Date temp = *this;
if (temp.d < days_of_month(temp.y, temp.m))
temp.d++;
else {
if (++temp.m > 12) {
temp.y++;
temp.m = 1;
}
temp.d = 1;
}
return temp;
}
// 曜日(日曜〜土曜が0〜6に対応)
int Date::day_of_week() const {
int yy = y;
int mm = m;
if (mm == 1 || mm == 2) {
yy--;
mm += 12;
}
return (yy + yy / 4 - yy / 100 + yy / 400 + (13 * mm + 8) / 5 + d) % 7;
}
// 文字列表現を返却
string Date::to_string() const {
ostringstream s;
s << y << "年" << m << "月" << d << "日";
return s.str();
}
// 挿入子の多重定義
ostream& operator<<(ostream& s, const Date& x) {
return s << x.to_string();
}
// DateTest.cpp
#include <iostream>
#include "Date.h"
using namespace std;
int main() {
Date today; // 今日の日付
cout << "今 日の日付:" << today << '\n';
cout << "昨 日の日付:" << today.preceding_day() << '\n';
cout << "一昨日の日付:" << today.preceding_day().preceding_day() << '\n';
cout << "明 日の日付:" << today.following_day() << '\n';
cout << "明後日の日付:" << today.following_day().following_day() << '\n';
cout << "元旦から" << today.day_of_year() << "日経過しています。\n";
cout << "今年は閏年"
<< (today.leap_year() ? "です。" : "ではありません。") << '\n';
int y, m, d;
cout << "西暦年:"; cin >> y;
cout << "その年は閏年"
<< (Date::leap_year(y) ? "です。" : "ではありません。") << '\n';
}
------------------------------------------------
新版明解C++入門編 p.473 演習13-1
上記の日付クラス Date.h に対して、以下の演算子関数を追加した日付クラスを作成せよ。
● 二つの日付が等しいかどうかを判定する等価演算子==
● 二つの日付が等しくないかどうかを判定する等価演算子!=
● 二つの日付の大小関係を判定する関係演算子>, >=, <, <=
※ より新しい日付のほうを大きいと判定すること。
● 二つの日付の減算を行う(何日離れているかを求める)減算演算子−
※ 左オペランドから右オペランドを引くこと(日付差を正負の値で示す)。
● 日付を翌日の日付に更新する前置および後置の増分演算子++
● 日付を前日の日付に更新する前置および後置の増分演算子−−
● 日付を n 日進めた日付に更新する複合代入演算子+=
● 日付を n 日戻した日付に更新する複合代入演算子−=
● 日付の n 日後の日付を求める加算演算子+
● 日付の n 日前の日付を求める減算演算子−
// Date.h
#ifndef ___Class_Date
#define ___Class_Date
#include <string>
#include <iostream>
class Date {
int y; // 西暦年
int m; // 月
int d; // 日
static int dmax[]; // 各月の日数(静的データメンバ)
static int days_of_month(int y, int m); // y年m月の日数(静的メンバ関数)
static int day_of_year(int y, int m, int d); // y年1月1日〜y年m月d日までの日数(静的メンバ関数)
public:
Date(); // デフォルトコンストラクタ
Date(int yy, int mm = 1, int dd = 1); // コンストラクタ
static bool leap_year(int year) { // 閏年なら true を返却(静的メンバ関数)
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
int year() const { return y; } // 年を返却
int month() const { return m; } // 月を返却
int day() const { return d; } // 日を返却
bool leap_year() const { // 閏年なら true を返却(非静的メンバ関数)
return leap_year(y);
}
Date preceding_day() const; // 前日の日付を返却
Date following_day() const; // 翌日の日付を返却
int day_of_year() const; // 年内の経過日数を返却
int day_of_week() const; // 曜日を返却
friend bool operator==(const Date& p, const Date& q);
friend bool operator!=(const Date& p, const Date& q);
friend bool operator <(const Date& p, const Date& q);
friend bool operator<=(const Date& p, const Date& q);
friend bool operator >(const Date& p, const Date& q);
friend bool operator>=(const Date& p, const Date& q);
friend int operator-(const Date& p, const Date& q);
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);
Date& operator+=(int n);
Date& operator-=(int n);
Date operator+(int n);
Date operator-(int n);
std::string to_string() const;
};
std::ostream& operator<<(std::ostream& s, const Date& x);
#endif
// Date.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <ctime>
#include <sstream>
#include <iomanip>
#include <iostream>
#include "Date.h"
using namespace std;
int Date::dmax[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int Date::days_of_month(int y, int m) {
return dmax[m - 1] + (leap_year(y) && m == 2);
}
int Date::day_of_year(int y, int m, int d) {
int days = d;
for (int i = 1; i < m; i++)
days += days_of_month(y, i);
return days;
}
Date::Date() {
time_t current = time(NULL);
struct tm* local = localtime(&current);
y = local->tm_year + 1900;
m = local->tm_mon + 1;
d = local->tm_mday;
}
Date::Date(int yy, int mm, int dd) {
y = yy;
m = mm;
d = dd;
}
int Date::day_of_year() const {
return day_of_year(y, m, d);
}
Date Date::preceding_day() const {
Date temp = *this;
if (temp.d > 1)
temp.d--;
else {
if (--temp.m < 1) {
temp.y--;
temp.m = 12;
}
temp.d = days_of_month(temp.y, temp.m);
}
return temp;
}
Date Date::following_day() const {
Date temp = *this;
if (temp.d < days_of_month(temp.y, temp.m))
temp.d++;
else {
if (++temp.m > 12) {
temp.y++;
temp.m = 1;
}
temp.d = 1;
}
return temp;
}
int Date::day_of_week() const {
int yy = y;
int mm = m;
if (mm == 1 || mm == 2) {
yy--;
mm += 12;
}
return (yy + yy / 4 - yy / 100 + yy / 400 + (13 * mm + 8) / 5 + d) % 7;
}
bool operator== (const Date& p, const Date& q) {
return p.y == q.y && p.m == q.m && p.d == q.d;
}
bool operator!=(const Date& p, const Date& q) {
return !(p == q);
}
bool operator<(const Date& p, const Date& q) {
if (p.y == q.y)
return p.day_of_year() < q.day_of_year();
else
return p.y < q.y;
}
bool operator<=(const Date& p, const Date& q) {
return p < q || p == q;
}
bool operator>(const Date& p, const Date& q) {
return !(p <= q);
}
bool operator>=(const Date& p, const Date& q) {
return !(p < q);
}
int operator-(const Date& p, const Date& q) {
int delta_d = p.day_of_year() - q.day_of_year();
if (p.y > q.y) {
for (int i = q.y; i < p.y; i++)
delta_d += (365 + Date::leap_year(i));
}
if (p.y < q.y) {
for (int i = p.y; i < q.y; i++)
delta_d -= (365 + Date::leap_year(i));
}
return delta_d;
}
Date& Date::operator++() {
*this = following_day();
return *this;
}
Date Date::operator++(int) {
Date temp = *this;
*this = following_day();
return temp;
}
Date& Date::operator--() {
*this = preceding_day();
return *this;
}
Date Date::operator--(int) {
Date temp = *this;
*this = preceding_day();
return temp;
}
Date& Date::operator+=(int n) {
for (int i = 0; i < n; i++)
++*this;
return *this;
}
Date& Date::operator-=(int n) {
for (int i = 0; i < n; i++)
--*this;
return *this;
}
Date Date::operator+(int n) {
Date temp = *this;
for (int i = 0; i < n; i++)
++temp;
return temp;
}
Date Date::operator-(int n) {
Date temp = *this;
for (int i = 0; i < n; i++)
--temp;
return temp;
}
string Date::to_string() const {
ostringstream s;
s << y << "年" << setw(2) << m << "月" << setw(2) << d << "日";
return s.str();
}
ostream& operator<<(ostream& s, const Date& x) {
return s << x.to_string();
}
// DateTest.cpp
#include <iomanip>
#include <iostream>
#include "Date.h"
using namespace std;
int main()
{
/*
Date today;
cout << "今 日の日付:" << today << '\n';
cout << "昨 日の日付:" << today.preceding_day() << '\n';
cout << "一昨日の日付:" << today.preceding_day().preceding_day() << '\n';
cout << "明 日の日付:" << today.following_day() << '\n';
cout << "明後日の日付:" << today.following_day().following_day() << '\n';
cout << "元旦から" << today.day_of_year() << "日経過しています。\n";
cout << "今年は閏年"
<< (today.leap_year() ? "です。" : "ではありません。") << '\n';
int y, m, d;
cout << "西暦年:"; cin >> y;
cout << "その年は閏年"
<< (Date::leap_year(y) ? "です。" : "ではありません。") << '\n';
*/
Date d0; cout << "d0 … " << d0 << '\n';
Date d1(2017, 11, 5); cout << "d1 … " << d1 << '\n';
Date d2(2016, 11, 4); cout << "d2 … " << d2 << '\n';
Date d3(2016, 11, 6); cout << "d3 … " << d3 << '\n';
Date d4(2017, 11, 5); cout << "d4 … " << d4 << '\n';
Date d5(2015, 11, 4); cout << "d5 … " << d5 << '\n';
Date d6(2015, 11, 6); cout << "d6 … " << d6 << '\n';
cout << boolalpha;
cout << "d0 == d1 … " << (d0 == d1) << '\n';
cout << "d0 != d1 … " << (d0 != d1) << '\n';
cout << "d0 == d2 … " << (d0 == d2) << '\n';
cout << "d0 != d2 … " << (d0 != d2) << '\n';
cout << "d0 < d1 … " << (d0 < d1) << '\n';
cout << "d0 <= d1 … " << (d0 <= d1) << '\n';
cout << "d0 > d1 … " << (d0 > d1) << '\n';
cout << "d0 >= d1 … " << (d0 >= d1) << '\n';
cout << "d0 < d2 … " << (d0 < d2) << '\n';
cout << "d0 <= d2 … " << (d0 <= d2) << '\n';
cout << "d0 > d2 … " << (d0 > d2) << '\n';
cout << "d0 >= d2 … " << (d0 >= d2) << '\n';
cout << "d1 - d2 … " << setw(4) << (d1 - d2) << '\n';
cout << "d2 - d1 … " << setw(4) << (d2 - d1) << '\n';
cout << "d1 - d3 … " << setw(4) << (d1 - d3) << '\n';
cout << "d3 - d1 … " << setw(4) << (d3 - d1) << '\n';
cout << "d1 - d5 … " << setw(4) << (d1 - d5) << '\n';
cout << "d5 - d1 … " << setw(4) << (d5 - d1) << '\n';
cout << "d1 - d6 … " << setw(4) << (d1 - d6) << '\n';
cout << "d6 - d1 … " << setw(4) << (d6 - d1) << '\n';
cout << "++d5 … " << ++d5 << '\n';
cout << "d5 … " << d5 << '\n';
cout << "d6++ … " << d6++ << '\n';
cout << "d6 … " << d6 << '\n';
cout << "--d5 … " << --d5 << '\n';
cout << "d5 … " << d5 << '\n';
cout << "d6-- … " << d6-- << '\n';
cout << "d6 … " << d6 << '\n';
cout << "d5 += 60 … " << (d5 += 60) << '\n';
cout << "d5 … " << d5 << '\n';
cout << "d5 -= 60 … " << (d5 -= 60) << '\n';
cout << "d5 … " << d5 << '\n';
cout << "d5 + 60 … " << (d5 + 60) << '\n';
cout << "d5 … " << d5 << '\n';
cout << "d5 - 60 … " << (d5 - 60) << '\n';
cout << "d5 … " << d5 << '\n';
}
--
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/6936462
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック