C++ Class 组合 - 构造函数和析构函数何时执行
C++ Class Composition - When does constructors and destructors get executed
请帮忙!我知道这个问题很长,但我真诚地没有任何人可以帮助我理解这个概念。
我有书中的代码,但我真的完全看不懂输出。该代码是关于两个 类 组合的示例,以及构造函数和析构函数的执行顺序。
抱歉,例子太长了:
// 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
我知道代码太长了,但真的想不出更简单的方法。输出如下。
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
现在,我的问题是……
为什么dateobject的构造函数只执行了两次,而析构函数执行了四次?据我了解, Date object 的构造函数也应该执行四次:
1. 在 main 'Date birth(7, 24, 1949)' 之后
2. 在 main 'Date hire(3, 12, 1988)' 之后
3. 在 Employee.h 'const Date birthDate' 之后
4. 'const Date hireDate' 在 Employee.h
我的#3 和#4 的原因是我无法想象 Employee object 构造函数在没有相同类型的空变量(或日期)的情况下复制 'birth' 和 'hire' object 在这种情况下)。
所以,我的理解是,在 Employee header 中,在创建私有成员 Date object 时,应该为每个成员执行一次显式默认 Date 构造函数(以 1/1/1900 作为成员变量 mn,dy , 年).
额外的 2 个 Date
析构函数调用是 Employee
有 2 个实例的结果。
当 Employee
被销毁时,那些实例也会被销毁。
此外,您只记录了 Date(int,int,int)
构造函数。编译器为 Date
提供了一个复制构造函数,在用 const Date &
.
初始化 Employee
的 2 Date
成员时使用
编辑:
如果要记录复制构造函数调用,则需要自己定义复制构造函数:
class Date
{
unsigned month;
unsigned day;
unsigned year;
public:
// Other stuff here
explicit Date(int, int, int);
Date(const Date &other) :
//
// Since this is a user-defined copy constructor,
// all member initialization must be done explicitly.
//
month{other.month},
day{other.day},
year{other.year}
{
cout << "Date copy constructor" << endl;
}
// Rest of stuff here
};
请帮忙!我知道这个问题很长,但我真诚地没有任何人可以帮助我理解这个概念。
我有书中的代码,但我真的完全看不懂输出。该代码是关于两个 类 组合的示例,以及构造函数和析构函数的执行顺序。
抱歉,例子太长了:
// 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
我知道代码太长了,但真的想不出更简单的方法。输出如下。
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
现在,我的问题是…… 为什么dateobject的构造函数只执行了两次,而析构函数执行了四次?据我了解, Date object 的构造函数也应该执行四次: 1. 在 main 'Date birth(7, 24, 1949)' 之后 2. 在 main 'Date hire(3, 12, 1988)' 之后 3. 在 Employee.h 'const Date birthDate' 之后 4. 'const Date hireDate' 在 Employee.h
我的#3 和#4 的原因是我无法想象 Employee object 构造函数在没有相同类型的空变量(或日期)的情况下复制 'birth' 和 'hire' object 在这种情况下)。 所以,我的理解是,在 Employee header 中,在创建私有成员 Date object 时,应该为每个成员执行一次显式默认 Date 构造函数(以 1/1/1900 作为成员变量 mn,dy , 年).
额外的 2 个 Date
析构函数调用是 Employee
有 2 个实例的结果。
当 Employee
被销毁时,那些实例也会被销毁。
此外,您只记录了 Date(int,int,int)
构造函数。编译器为 Date
提供了一个复制构造函数,在用 const Date &
.
Employee
的 2 Date
成员时使用
编辑:
如果要记录复制构造函数调用,则需要自己定义复制构造函数:
class Date
{
unsigned month;
unsigned day;
unsigned year;
public:
// Other stuff here
explicit Date(int, int, int);
Date(const Date &other) :
//
// Since this is a user-defined copy constructor,
// all member initialization must be done explicitly.
//
month{other.month},
day{other.day},
year{other.year}
{
cout << "Date copy constructor" << endl;
}
// Rest of stuff here
};