بخش ۷ - مفاهیم پایهی شیءگرایی
در این بخش، تعریف یک کلاس ساده برای نگهداری تاریخ مورد بررسی قرار میگیرد. این کلاس طی مثالهای متوالی کاملتر میشود.
فهرست مثالها
پیادهسازی ابتدایی تاریخ در قالب یک کلاس
#include <iostream> #include <cstdlib> using namespace std; class Date { public: void set_date(int d, int m, int y); void print_date(); private: int day; int month; int year; }; void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || (m < 7 && d > 31) || (m > 6 && m < 12 && d > 30) || (m == 12 && d > 29)) abort(); day = d; month = m; year = y; } void Date::print_date() { cout << day << '/' << month << '/' << year << endl; } int main() { Date bd; bd.print_date(); bd.set_date(31, 6, 1352); bd.print_date(); // bd.day = 14; }چه خواهد شد ...؟
اضافه شدن سازنده (constructor) به کلاس تاریخ
#include <iostream> #include <cstdlib> using namespace std; class Date { public: Date(int d, int m, int y); // ... other members from the previous example void set_date(int d, int m, int y); void print_date(); private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || (m < 7 && d > 31) || (m > 6 && m < 12 && d > 30) || (m == 12 && d > 29)) abort(); day = d; month = m; year = y; } void Date::print_date() { cout << day << '/' << month << '/' << year; } int main() { // Date bd; Date bd(31, 6, 1352); bd.print_date(); cout << '\n'; }
دسترسی به اعضای خصوصی تاریخ از طریق getter ها
#include <iostream> #include <cstdlib> using namespace std; class Date { public: // ... other members from the previous example Date(int d, int m, int y); void set_date(int d, int m, int y); void print_date(); int get_day() { return day; } int get_month() { return month; } int get_year() { return year; } private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || (m < 7 && d > 31) || (m > 6 && m < 12 && d > 30) || (m == 12 && d > 29)) abort(); day = d; month = m; year = y; } void Date::print_date() { cout << day << '/' << month << '/' << year; } int main() { Date bd(31, 6, 1352); bd.print_date(); cout << '\n'; cout << bd.get_day() << endl; }
استفاده از توابع معمولی (نه توابع عضو) به عنوان توابع کمکی
#include <iostream> #include <cstdlib> using namespace std; // ... definition of class Date class Date { public: Date(int d, int m, int y); void set_date(int d, int m, int y); void print_date(); int get_day() { return day; } int get_month() { return month; } int get_year() { return year; } private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } bool is_leap_year(int year) { int r = year % 33; return r==1 || r==5 || r==9 || r==13 || r==17 || r==22 || r==26 || r==30; } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || (m < 7 && d > 31) || (m > 6 && m < 12 && d > 30) || (m == 12 && !is_leap_year(y) && d > 29) || (m == 12 && is_leap_year(y) && d > 30)) abort(); day = d; month = m; year = y; } void Date::print_date() { cout << day << '/' << month << '/' << year; } int main() { Date bd(31, 6, 1352); bd.print_date(); cout << '\n'; cout << bd.get_day() << endl; }
جدا کردن تابع days_of_month به منظور خوانا کردن برنامه
#include <iostream> #include <cstdlib> using namespace std; // ... definition of class Date class Date { public: Date(int d, int m, int y); void set_date(int d, int m, int y); void print_date(); int get_day() { return day; } int get_month() { return month; } int get_year() { return year; } private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } bool is_leap_year(int year) { int r = year % 33; return r==1 || r==5 || r==9 || r==13 || r==17 || r==22 || r==26 || r==30; } int days_of_month(int m, int y) { if (m < 7) return 31; else if (m < 12) return 30; else if (m == 12) return is_leap_year(y) ? 30 : 29; else abort(); } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || d > days_of_month(m, y)) abort(); day = d; month = m; year = y; } void Date::print_date() { cout << day << '/' << month << '/' << year; } int main() { Date bd(31, 6, 1352); bd.print_date(); cout << '\n'; cout << bd.get_day() << endl; }
اضافه کردن یک تابع عضو برای جلوبردن تاریخ به اندازهی یک روز
#include <iostream> #include <cstdlib> using namespace std; class Date { public: // ... definition of other members Date(int d, int m, int y); void set_date(int d, int m, int y); void print_date(); void inc_one_day(); int get_day() { return day; } int get_month() { return month; } int get_year() { return year; } private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } bool is_leap_year(int year) { int r = year % 33; return r==1 || r==5 || r==9 || r==13 || r==17 || r==22 || r==26 || r==30; } int days_of_month(int m, int y) { if (m < 7) return 31; else if (m < 12) return 30; else if (m == 12) return is_leap_year(y) ? 30 : 29; else abort(); } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || d > days_of_month(m, y)) abort(); day = d; month = m; year = y; } void Date::inc_one_day() { day++; if (day > days_of_month(month, year)) { day = 1; month++; if (month > 12) { month = 1; year++; } } } void Date::print_date() { cout << day << '/' << month << '/' << year; } int main() { Date bd(31, 6, 1352); bd.print_date(); cout << '\n'; cout << bd.get_day() << endl; }
مقایسهی تساوی دو تاریخ در قالب یک تابع عضو (equals) و محاسبهی فاصلهی دو تاریخ در قالب یک تابع کمکی (days_between) پیادهسازی شدهاند.
#include <iostream> #include <cstdlib> using namespace std; class Date { public: // ... definition of other members Date(int d, int m, int y); void set_date(int d, int m, int y); void print_date(); void inc_one_day(); bool equals(Date d); int get_day() { return day; } int get_month() { return month; } int get_year() { return year; } private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } bool is_leap_year(int year) { int r = year % 33; return r==1 || r==5 || r==9 || r==13 || r==17 || r==22 || r==26 || r==30; } int days_of_month(int m, int y) { if (m < 7) return 31; else if (m < 12) return 30; else if (m == 12) return is_leap_year(y) ? 30 : 29; else abort(); } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || d > days_of_month(m, y)) abort(); day = d; month = m; year = y; } void Date::inc_one_day() { day++; if (day > days_of_month(month, year)) { day = 1; month++; if (month > 12) { month = 1; year++; } } } void Date::print_date() { cout << day << '/' << month << '/' << year << endl; } bool Date::equals(Date d) { return day == d.day && month == d.month && year == d.year; } int days_between(Date d1, Date d2) { // Assuming d1 is not later than d2 int count = 1; while (!d1.equals(d2)) { d1.inc_one_day(); count++; } return count; } int main() { Date bd(31, 6, 1352); Date today(10, 12, 1391); cout << days_between(bd, today) << endl; }
تبدیل یک رشته به تاریخ بدون درنظر گرفتن خطاهای فرمت ورودی
#include <iostream> #include <string> #include <cstdlib> using namespace std; // ... definition of class Date class Date { public: Date(int d, int m, int y); void set_date(int d, int m, int y); void print_date(); void inc_one_day(); bool equals(Date d); int get_day() { return day; } int get_month() { return month; } int get_year() { return year; } private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } bool is_leap_year(int year) { int r = year % 33; return r==1 || r==5 || r==9 || r==13 || r==17 || r==22 || r==26 || r==30; } int days_of_month(int m, int y) { if (m < 7) return 31; else if (m < 12) return 30; else if (m == 12) return is_leap_year(y) ? 30 : 29; else abort(); } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || d > days_of_month(m, y)) abort(); day = d; month = m; year = y; } void Date::inc_one_day() { day++; if (day > days_of_month(month, year)) { day = 1; month++; if (month > 12) { month = 1; year++; } } } void Date::print_date() { cout << day << '/' << month << '/' << year << endl; } bool Date::equals(Date d) { return day == d.day && month == d.month && year == d.year; } Date str_to_date(string s) { //TODO: Handle formatting errors int slash_pos = s.find('/'); int d = atoi(s.substr(0, slash_pos).c_str()); s = s.substr(slash_pos + 1); slash_pos = s.find('/'); int m = atoi(s.substr(0, slash_pos).c_str()); int y = atoi(s.substr(slash_pos + 1).c_str()); return Date(d, m, y); } int main() { string s = "12/01/1359"; Date d = str_to_date(s); d.print_date(); str_to_date("10/01/1300").print_date(); }
میتوان از کلاس تاریخ به عنوان تایپ عناصر یک بردار استفاده کرد
#include <vector> #include <iostream> #include <cstdlib> using namespace std; // ... definition of class Date class Date { public: Date(int d, int m, int y); void set_date(int d, int m, int y); void print_date(); void inc_one_day(); bool equals(Date d); int get_day() { return day; } int get_month() { return month; } int get_year() { return year; } private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } bool is_leap_year(int year) { int r = year % 33; return r==1 || r==5 || r==9 || r==13 || r==17 || r==22 || r==26 || r==30; } int days_of_month(int m, int y) { if (m < 7) return 31; else if (m < 12) return 30; else if (m == 12) return is_leap_year(y) ? 30 : 29; else abort(); } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || d > days_of_month(m, y)) abort(); day = d; month = m; year = y; } void Date::inc_one_day() { day++; if (day > days_of_month(month, year)) { day = 1; month++; if (month > 12) { month = 1; year++; } } } void Date::print_date() { cout << day << '/' << month << '/' << year << endl; } bool Date::equals(Date d) { return day == d.day && month == d.month && year == d.year; } int main() { Date bd(30, 12, 1387); vector<Date> dates; dates.push_back(bd); dates.push_back(Date(1, 1, 1)); dates[0].print_date(); vector<Date> dates2(100, Date(1,1,1)); }
در این مثال، کلاسی به نام Person تعریف میشود که یکی از فیلدهای آن تاریخ تولد (از نوع Date) است.
#include <iostream> #include <string> #include <cstdlib> #include <vector> using namespace std; // ... definition of class Date class Date { public: Date(int d, int m, int y); void set_date(int d, int m, int y); void print_date(); void inc_one_day(); bool equals(Date d); int get_day() { return day; } int get_month() { return month; } int get_year() { return year; } private: int day; int month; int year; }; Date::Date(int d, int m, int y) { set_date(d, m, y); } bool is_leap_year(int year) { int r = year % 33; return r==1 || r==5 || r==9 || r==13 || r==17 || r==22 || r==26 || r==30; } int days_of_month(int m, int y) { if (m < 7) return 31; else if (m < 12) return 30; else if (m == 12) return is_leap_year(y) ? 30 : 29; else abort(); } void Date::set_date(int d, int m, int y) { if (y < 0 || m < 1 || m > 12 || d < 1 || d > days_of_month(m, y)) abort(); day = d; month = m; year = y; } void Date::inc_one_day() { day++; if (day > days_of_month(month, year)) { day = 1; month++; if (month > 12) { month = 1; year++; } } } void Date::print_date() { cout << day << '/' << month << '/' << year << endl; } bool Date::equals(Date d) { return day == d.day && month == d.month && year == d.year; } Date str_to_date(string s) { //TODO: Handle formatting errors int slash_pos = s.find('/'); int d = atoi(s.substr(0, slash_pos).c_str()); s = s.substr(slash_pos + 1); slash_pos = s.find('/'); int m = atoi(s.substr(0, slash_pos).c_str()); int y = atoi(s.substr(slash_pos + 1).c_str()); return Date(d, m, y); } class Person { public: Person(string n, int d, int m, int y); Date get_bdate() { return bdate; } string get_name() { return name; } private: string name; Date bdate; }; Person::Person(string n, int d, int m, int y) : bdate(d, m, y) { if (n == "") abort(); name = n; } int main() { vector<Person> vp; vp.push_back(Person("gholam", 2, 7, 1370)); vp.push_back(Person("ghamar", 3, 12, 1368)); vp.push_back(Person("alaleh", 12, 2, 1360)); cout << "Today? "; string today_str; cin >> today_str; Date today = str_to_date(today_str); for (int i = 0; i < vp.size(); i++) if (vp[i].get_bdate().equals(today)) cout << "Happy Birth Day " << vp[i].get_name() << "!\n"; }
- یک متد به نام compare به تاریخ اضافه کنید طوری که d1.compare(d2) در حالتی که d1 < d2، مقدار منفی یک، در حالتی که d1 = d2، مقدار صفر و در حالتی که d1 > d2 مقدار یک را برگرداند.
- در تعریف تابع days_between فرض شده است که پارامتر اول کوچکتر یا مساوی پارامتر دوم است. تعریف این تابع را طوری تغییر دهید که این محدودیت برداشته شود.
- با فرض این که ۱ فروردین ۱ جمعه است، متدی به کلاس تاریخ به نام day_of_week اضافه کنید که مشخص کند تاریخ مربوطه چه روزی از هفته است. مقدار که این تابع برمیگرداند یکی از رشتههای "sun"، "sat" تا "fri" است.
- هدف این تمرین طراحی کلاسی به نام Time است که همان طور که از نام آن پیداست، قرار است برای ذخیره کردن زمان استفاده میشود. این کلاس را طوری طراحی و پیادهسازی کنید که امکانات زیر را داشته باشد:
- فیلدهای مناسب برای ذخیره سازی دقیقه و ساعت
- یک سازنده که ورودی آن دقیقه و ساعت باشد
- یک سازنده که ورودی آن تنها ساعت باشد (در این حالت دقیقه باید صفر در نظر گرفته شود)
- یک متد برای تغییر دقیقه و ساعت
- دو متد برای برگرداندن مقدار دقیقه و ساعت
- یک متد که ورودی آن شیء دیگری از کلاس Time است و مانند تمرین اول دو زمان را با هم مقایسه میکند
- متدی که بر اساس زمان رشته ای برگرداند که بگوید چه وقتی از روز است. فرض کنید از ابتدای یک روز تا ساعت ۱۱:۵۹ صبح، ۱۲:۰۰ ظهر، از ۱۲:۰۱ تا ۱۶:۵۹ بعدازظهر، از ۱۷:۰۰ تا ۱۹:۵۹ عصر و بعد از آن شب محسوب میشود.
- هر جا قرار است زمان ذخیره شده تغییر کند، باید بررسی شود که اعداد وارد شده قابل قبول باشد و در غیر این صورت اجرای برنامه خاتمه یابد.
- برای آزمودن امکانات این کلاس یک برنامه ساده در تابع main بنویسید.
- دقت کنید که فیلدهای کلاس نباید به صورت عمومی (public) قابل دسترسی باشند.