Accessing Data Members

As it is currently defined, the Date class does not permit any access to its individual month, day, and year components. For example, you cannot read or modify the month value of a Date object. To remedy this, you can revise the Date class as follows:

class Date

{

public:

Date( int mn, int dy, int yr ); // Constructor

// Member functions:

int getMonth(); // Get month

int getDay(); // Get day

int getYear(); // Get year

void setMonth( int mn ); // Set month

void setDay( int dy ); // Set day

void setYear( int yr ); // Set year

void display(); // Print date

~Date(); // Destructor

private:

int month, day, year; // Private data members

};

This version of Date includes member functions to read and modify the month, day, and year members. The function definitions are as follows:

inline int Date::getMonth()

{

return month;

}

inline int Date::getDay()

{

return day;

}

inline int Date::getYear()

{

return year;

}

void Date::setMonth( int mn )

{

month = max( 1, mn );

month = min( month, 12 );

}

void Date::setDay( int dy )

{

static int length[] = { 0, 31, 28, 31, 30, 31, 30,

31, 31, 30, 31, 30, 31 };

day = max( 1, dy );

day = min( day, length[month] );

}

void Date::setYear( int yr )

{

year = max( 1, yr );

}

The various get functions simply return the value of the appropriate data member. However, the set functions do not simply assign a new value to a data member. These functions also check the validity of the specified value before assigning it. This is another way to ensure that Date objects contain valid values.

The following example uses these new member functions:

void main()

{

int i;

Date deadline( 3, 10, 1980 );

i = deadline.getMonth(); // Read month value

deadline.setMonth( 4 ); // Modify month value

deadline.setMonth( deadline.getMonth() + 1 ); // Increment

}

Notice that the get functions are declared inline because they're so short. Because those functions have no function call overhead, calling them is as efficient as directly accessing public data members.

Member functions can also be declared inline without using the inline keyword. Instead, you can place the body of the function inside the class declaration, as follows:

class Date

{

public:

Date( int mn, int dy, int yr );

int getMonth() { return month; } // Inline member functions

int getDay() { return day; }

int getYear() { return year; }

// etc....

};

This style of declaration has precisely the same effect as using the inline keyword with separate function definitions. You can use whichever style you find more readable.

Now that the class has member functions to set its values, you can change the way a Date object is constructed. You can overload constructors in the same way you overload other functions. The following example defines two versions of Date's constructor, one that takes parameters and one that doesn't:

class Date

{

public:

Date(); // Constructor with no parameters

Date( int mn, int dy, int yr ); // Constructor with parameters

// etc....

};

Date::Date()

{

month = day = year = 1; // Initialize data members

}

Date::Date( int mn, int dy, int yr )

{

setMonth( mn );

setDay( dy );

setYear( yr );

}

void main()

{

Date myDate; // Declare a date without arguments

Date yourDate( 12, 25, 1990 );

myDate.setMonth( 3 ); // Set values for myDate

myDate.setDay( 12 );

myDate.setYear( 1985 );

}

The declaration of myDate doesn't specify any initial values. As a result, the first constructor is used to create myDate and initialize it with the default value “January 1, 1.” The values for myDate are specified later with the set functions. In contrast, the declaration of yourDate specifies three arguments. The second constructor is used to create yourDate, and this constructor calls the member functions to set the data members to the specified values. It is legal for a constructor to call member functions, as long as those functions don't read any uninitialized data members.

The first constructor in the example above is known as a “default constructor,” because it can be called without arguments. If you define a default constructor, the compiler calls it automatically in certain situations; see topic , “Member Objects,” and topic , “Arrays of Class Objects” in Chapter 6.