UNIONS ■ 259 ᮀ Memory Usage In normal classes, each data member belonging to an object has its own separate memory space. However, a union is a class whose members are stored in the same memory space. Each data member has the same starting address in memory. Of course, a union cannot store various data members at the same address simultaneously. However, a union does provide for more versatile usage of memory space. ᮀ Definition Syntactically speaking, a union is distinguished from a class defined as a class or struct only by the keyword union. Example: union Number { long n; double x; }; Number number1, number2; This example defines the union Number and two objects of the same type. The union Number can be used to store either integral or floating-point numbers. Unless a private label is used, all union members are assumed to be public. This is similar to the default setting for structures. This allows direct access to the members n and x in the union Number. Example: number1.n = 12345; // Storing an integer number1.n *= 3; // and multiply by 3. number2.x = 2.77; // Floating point number The programmer must ensure that the current content of the union is interpreted cor- rectly. This is normally achieved using an additional type field that identifies the current content. The size of a union type object is derived from the longest data member, as all data members begin at the same memory address. If we look at our example, the union Number, this size is defined by the double member, which defaults to 8 == sizeof(double) byte. The example opposite defines the union WordByte that allows you to read or write to a 16-bit memory space byte for byte or as a unit. exercise 260 ■ CHAPTER 13 DEFINING CLASSES struct tm { int tm_sec; // 0 - 59(60) int tm_min; // 0 - 59 int tm_hour; // 0 - 23 int tm_mday; // Day of month: 1 - 31 int tm_mon; // Month: 0 - 11 (January == 0) int tm_year; // Years since 1900 (Year - 1900) int tm_wday; // Weekday: 0 - 6 (Sunday == 0) int tm_yday; // Day of year: 0 - 365 int tm_isdst; // Flag for summer-time }; #include <iostream> #include <ctime> using namespace std; struct tm *ptr; // Pointer to struct tm. time_t sec; // For seconds. . . . time(&sec); // To get the present time. ptr = localtime(&sec); // To initialize a struct of // type tm and return a // pointer to it. cout << "Today is the " << ptr->tm_yday + 1 << ". day of the year " << ptr->tm_year << endl; . . . ■ EXERCISE Struct tm in header file ctime Sample calls to functions time( ) and localtime( ) EXERCISE ■ 261 Use the functions declared in ctime time_t time(time_t *ptrSec) struct tm *localtime(const time_t *ptrSec); ✓ NOTE Exercise A program needs a class to represent the date. ■ Define the class Date for this purpose using three integral data members for day, month, and year.Additionally, declare the following methods: void init( int month, int day, int year); void init(void); void print(void); Store the definition of the class Date in a header file. ■ Implement the methods for the class Date in a separate source file: 1. The method print() outputs the date to standard output using the format Month-Day-Year. 2. The method init() uses three parameters and copies the values passed to it to corresponding members. A range check is not required at this stage, but will be added later. 3. The method init() without parameters writes the current date to the corresponding members. The structure tm and sample calls to this function are included oppo- site.The type time_t is defined as long in ctime. The function time() returns the system time expressed as a num- ber of seconds and writes this value to the variable referenced by ptr- Sec . This value can be passed to the function localtime() that converts the number of seconds to the local type tm date and returns a pointer to this structure. ■ Test the class Date using an application program that once more is stored in a separate source file.To this end, define two objects for the class and display the current date. Use object assignments and—as an additional exercise—references and pointers to objects. solution 262 ■ CHAPTER 13 DEFINING CLASSES ■ SOLUTION // // date.h // First Definition of class Date. // #ifndef _DATE_ // Avoid multiple inclusion. #define _DATE_ class Date { private: // Sheltered members: short month, day, year; public: // Public interface: void init(void); void init( int month, int day, int year); void print(void); }; #endif // _DATE_ // // date.cpp // Implementing the methods of class Date. // #include "date.h" #include <iostream> #include <ctime> using namespace std; // void Date::init(void) // Get the present date and { // assign it to data members. struct tm *ptr; // Pointer to struct tm. time_t sec; // For seconds. time(&sec); // Get the present date. ptr = localtime(&sec); // Initialize a struct of // type tm and return a // pointer to it. month = (short) ptr->tm_mon + 1; day = (short) ptr->tm_mday; year = (short) ptr->tm_year + 1900; } SOLUTION ■ 263 // void Date::init( int m, int d, int y) { month = (short) m; day = (short) d; year = (short) y; } // void Date::print(void) // Output the date { cout << month << '-' << day << '-' << year << endl; } // // date_t.cpp // Using objects of class Date. // #include "date.h" #include <iostream> using namespace std; int main() { Date today, birthday, aDate; today.init(); birthday.init( 12, 11, 1997); cout << "Today's date: "; today.print(); cout << "\n Felix' birthday: "; birthday.print(); cout << " \n" "Some testing outputs:" << endl; aDate = today; // Assignment ok aDate.print(); Date *pDate = &birthday; // Pointer to birthday pDate->print(); Date &holiday = aDate; // Reference to aDate. holiday.init( 1, 5, 2000); // Writing to aDate. aDate.print(); // holiday.print(); return 0; } This page intentionally left blank 265 Methods This chapter describes ■ how constructors and destructors are defined to create and destroy objects ■ how inline methods, access methods, and read-only methods can be used ■ the pointer this, which is available for all methods, and ■ what you need to pay attention to when passing objects as arguments or returning objects. chapter 14 266 ■ CHAPTER 14 METHODS // account.h // Defining class Account with two constructors. // #ifndef _ACCOUNT_ #define _ACCOUNT_ #include <string> using namespace std; class Account { private: // Sheltered members: string name; // Account holder unsigned long nr; // Account number double state; // State of the account public: // Public interface: Account( const string&, unsigned long, double ); Account( const string& ); bool init( const string&, unsigned long, double); void display(); }; #endif // _ACCOUNT_ // Within file account.cpp: Account::Account( const string& a_name, unsigned long a_nr, double a_state) { nr = a_nr; name = a_name; state = a_state; } Account::Account( const string& a_name ) { name = a_name; nr = 1111111; state = 0.0; } ■ CONSTRUCTORS Class Account with constructors Defining the constructors CONSTRUCTORS ■ 267 ᮀ The Task of a Constructor Traditional programming languages only allocate memory for a variable being defined. The programmer must ensure that the variable is initialized with suitable values. An object of the class Account, as described in the previous chapter, does not possess any valid values until the method init() is called. Non-initialized objects can lead to serious runtime errors in your programs. To avoid errors of this type, C++ performs implicit initialization when an object is defined. This ensures that objects will always have valid data to work on. Initialization is performed by special methods known as constructors. ᮀ Declaration Constructors can be identified by their names. In contrast to other member functions, the following applies: ■ the name of the constructor is also the class name ■ a constructor does not possess a return type—not even void. Constructors are normally declared in the public section of a class. This allows you to create objects wherever the class definition is available. Constructors can be overloaded, just like other functions. Constructors belonging to a class must be distinguishable by their signature (that is, the number, order, and type of parameters). This allows for different methods of object initialization. The example opposite shows an addition to the Account class. The class now has two constructors. ᮀ Definition Since a constructor has the same name as its class, the definition of a constructor always begins with Class_name::Class_name In the definition itself, the arguments passed can be checked for validity before they are copied to the corresponding data members. If the number of arguments is smaller than the number of data members, the remaining members can be initialized using default val- ues. Constructors can also perform more complex initialization tasks, such as opening files, allocating memory, and configuring interfaces. 268 ■ CHAPTER 14 METHODS // account2_t.cpp // Using the constructors of class Account. // #include "account.h" int main() { Account giro("Cheers, Mary", 1234567, -1200.99 ), save("Lucky, Luke"); Account depot; // Error: no default constructor // defined. giro.display(); // To output save.display(); Account temp("Funny, Susy", 7777777, 1000000.0); save = temp; // ok: Assignment of // objects possible. save.display(); // Or by the presently available method init(): save.init("Lucky, Luke", 7654321, 1000000.0); save.display(); return 0; } ■ CONSTRUCTOR CALLS Sample program . endl; aDate = today; // Assignment ok aDate.print(); Date *pDate = &birthday; // Pointer to birthday pDate->print(); Date &holiday = aDate; // Reference to aDate. holiday.init( 1,. Memory Usage In normal classes, each data member belonging to an object has its own separate memory space. However, a union is a class whose members are stored in the same memory space. Each data member. account.cpp: Account::Account( const string& a_ name, unsigned long a_ nr, double a_ state) { nr = a_ nr; name = a_ name; state = a_ state; } Account::Account( const string& a_ name ) { name = a_ name; nr