بخش ۷ - مفاهیم پایه‌ی شیءگرایی

در این بخش، تعریف یک کلاس ساده برای نگهداری تاریخ مورد بررسی قرار می‌گیرد. این کلاس طی مثال‌های متوالی کامل‌تر می‌شود.

فهرست مثال‌ها

کلاس تاریخ - مرحله‌ی اول

پیاده‌سازی ابتدایی تاریخ در قالب یک کلاس

01_DateBasic.cpp
#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.set_date(31, 6, 1352);
    bd.print_date();
    // bd.day = 14;
}


				
کلاس تاریخ - سازنده

اضافه شدن سازنده (constructor) به کلاس تاریخ

02_DateConstr.cpp
class Date {
public:
    Date(int d, int m, int y);
};

Date::Date(int d, int m, int y)
{
    set_date(d, m, y);
}

int main()
{
    // Date bd;
    Date bd(31, 6, 1352);
    bd.print_date();
    cout << '\n';
}
				
کلاس تاریخ - توابع دسترسی

دسترسی به اعضای خصوصی تاریخ از طریق getter ها

03_DateAccessors.cpp
class Date {
public:
    int get_day() { return day; }
    int get_month() { return month; }
    int get_year() { return year; }
};
                                                                            
int main()
{
    Date bd(31, 6, 1352);
    bd.print_date();
    cout << '\n';
    cout << bd.get_day() << endl;
}
				
کلاس تاریخ - توابع کمکی

استفاده از توابع معمولی (نه توابع عضو) به عنوان توابع کمکی

04_DateHelper.cpp

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;
}

				
کلاس تاریخ - خواناتر کردن اعتبارسنجی

جدا کردن تابع days_of_month به منظور خوانا کردن برنامه

05_DateValidate.cpp

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;
}

				
کلاس تاریخ - جلوبردن تاریخ

اضافه کردن یک تابع عضو برای جلوبردن تاریخ به اندازه‌ی یک روز

06_DateIncOneDay.cpp

class Date {
public:
    void inc_one_day();
};

void Date::inc_one_day()
{
    day++;
    if (day > days_of_month(month, year)) {
        day = 1;
        month++;
        if (month > 12) {
            month = 1;
            year++;
        }
    }
}

				
کلاس تاریخ - مقایسه‌ی تاریخ‌ها

مقایسه‌ی تساوی دو تاریخ در قالب یک تابع عضو (equals) و محاسبه‌ی فاصله‌ی دو تاریخ در قالب یک تابع کمکی (days_between) پیاده‌سازی شده‌اند.

07_DateDiff.cpp

class Date {
public:
    bool equals(Date d);
};
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;
}
				
کلاس تاریخ - تبدیل رشته به تاریخ

تبدیل یک رشته به تاریخ بدون درنظر گرفتن خطاهای فرمت ورودی

08_StrToDate.cpp

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();
}
				
کلاس تاریخ - برداری از تاریخ‌ها

می‌توان از کلاس تاریخ به عنوان تایپ عناصر یک بردار استفاده کرد

09_DateVector.cpp
#include <vector>
                                                                                

class Date {
public:
};

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) است.

10_Composition.cpp
                                                                                

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";
}