jeudi 12 mars 2015

C++ Class Composition / When does the constructor and destructors get executed?


PLEASE HELP! I know the question is lengthy, but I sincerely don't have anybody who can help me understand the concept.


I have a code from a book, but I sincerely could not understand the output at all. The code is an example regarding two classes composition, and in what order the constructors and destructors are executed.


Sorry for lengthy example:



// Fig. 10.8: Date.h
// Date class definition; Member functions defined in Date.cpp
#ifndef DATE_H
#define DATE_H

class Date
{
public:
static const unsigned int monthsPerYear = 12; // number of months in a year
explicit Date( int = 1, int = 1, int = 1900 ); // default constructor
void print() const; // print date in month/day/year format
~Date(); // provided to confirm destruction order

private:
unsigned int month; // 1-12 (January-December)
unsigned int day; // 1-31 based on month
unsigned int year; // any year

// utility function to check if day is proper for month and year
unsigned int checkDay( int ) const;
}; // end class Date

#endif

// Fig. 10.9: Date.cpp
// Date class member-function definitions.
#include <array>
#include <iostream>
#include <stdexcept>
#include "Date.h" // include Date class definition
using namespace std;

// constructor confirms proper value for month; calls
// utility function checkDay to confirm proper value for day
Date::Date( int mn, int dy, int yr )
{
if ( mn > 0 && mn <= monthsPerYear ) // validate the month
month = mn;
else
throw invalid_argument( "month must be 1-12" );

year = yr; // could validate yr
day = checkDay( dy ); // validate the day

// output Date object to show when its constructor is called
cout << "Date object constructor for date ";
print();
cout << endl;
} // end Date constructor

// print Date object in form month/day/year
void Date::print() const
{
cout << month << '/' << day << '/' << year;
} // end function print

// output Date object to show when its destructor is called

Date::~Date()
{
cout << "Date object destructor for date ";
print();
cout << endl;
} // end ~Date destructor

// utility function to confirm proper day value based on // month and year; handles leap years, too
unsigned int Date::checkDay( int testDay ) const
{
static const array < int, monthsPerYear + 1 > daysPerMonth =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

// determine whether testDay is valid for specified month
if ( testDay > 0 && testDay <= daysPerMonth[ month ] )
return testDay;

// February 29 check for leap year
if ( month == 2 && testDay == 29 && ( year % 400 == 0 || ( year % 4 == 0 && year % 100 != 0 ) ) )
return testDay;

throw invalid_argument( "Invalid day for current month and year" );
} // end function checkDay

// Fig. 10.10: Employee.h
// Employee class definition showing composition. // Member functions defined in Employee.cpp.
#ifndef EMPLOYEE_H
#define EMPLOYEE_H

#include <string>
//#include "Date.h" // include Date class definition using namespace std;
class Employee
{
public:
Employee( const string &, const string &, const Date &, const Date & );
void print() const;
~Employee(); // provided to confirm destruction order
private:
string firstName; // composition: member object
string lastName; // composition: member object
const Date birthDate; // composition: member object
const Date hireDate; // composition: member object 23
}; // end class Employee

#endif

// Fig. 10.11: Employee.cpp
// Employee class member-function definitions.
#include <iostream>
#include "Employee.h" // Employee class definition
#include "Date.h" // Date class definition
using namespace std;

// constructor uses member initializer list to pass initializer
// values to constructors of member objects
Employee::Employee( const string &first, const string &last, const Date &dateOfBirth, const Date &dateOfHire )
: firstName( first ), lastName( last ), birthDate( dateOfBirth ), hireDate( dateOfHire )
{
// output Employee object to show when constructor is called
cout << "Employee object constructor: " << firstName << ' ' << lastName << endl;
} // end Employee constructor

// print Employee object
void Employee::print() const
{
cout << lastName << ", " << firstName << " Hired: ";
hireDate.print();

cout << " Birthday: ";
birthDate.print();

cout << endl;
} // end function print

// output Employee object to show when its destructor is called
Employee::~Employee()
{
cout << "Employee object destructor: " << lastName << ", " << firstName << endl;
} // end ~Employee destructor

// Fig. 10.12: fig10_12.cpp
// Demonstrating composition--an object with member objects.
#include <iostream>
//#include "Employee.h" // Employee class definition
using namespace std;

int main()
{
Date birth( 7, 24, 1949 );
Date hire( 3, 12, 1988 );
Employee manager( "Bob", "Blue", birth, hire );

cout << endl;
manager.print();
}//endmain


I know the code is too long, but really couldn't think of a way to do this easier. The output is below.


Date object constructor for date 7/24/1949 Date object constructor for date 3/12/1988 Employee object constructor: Bob Blue


Blue, Bob Hired: 3/12/1988 Birthday: 7/24/1949 Employee object destructor: Blue, Bob Date object destructor for date 3/12/1988 Date object destructor for date 7/24/1949 Date object destructor for date 3/12/1988 Date object destructor for date 7/24/1949


Now, my question is... Why is constructor of date object is only executed twice while the destructor is executed four times? To my understanding, the constructor of Date object should also be executed four times: 1. Upon 'Date birth(7, 24, 1949)' in main 2. Upon 'Date hire(3, 12, 1988)' in main 3. Upon 'const Date birthDate' in Employee.h 4. Upon 'const Date hireDate' in Employee.h


The reason for my #3 and #4 is that I can't imagine Employee object constructor to copy 'birth' and 'hire' without same type of empty variables(or Date object in this case). So, my understanding is that in Employee header, upon private member Date object creation, explicit default Date constructor should be executed once for each of them (with 1/1/1900 as member variables mn, dy, yr).




Aucun commentaire:

Enregistrer un commentaire