Composition: Objects as Members of Classes


 

An AlarmClock object needs to know when it is supposed to sound its alarm, so why not include a Time object as a member of the AlarmClock class? Such a capability is called composition and is sometimes referred to as a has-a relationship. A class can have objects of other classes as members.

Software Engineering Observation 10.5

A common form of software reusability is composition, in which a class has objects of other classes as members.


When an object is created, its constructor is called automatically. Previously, we saw how to pass arguments to the constructor of an object we created in main. This section shows how an object's constructor can pass arguments to member-object constructors, which is accomplished via member initializers. Member objects are constructed in the order in which they are declared in the class definition (not in the order they are listed in the constructor's member initializer list) and before their enclosing class objects (sometimes called host objects) are constructed.


[Page 535]

The program of Figs. 10.1010.14 uses class Date (Figs. 10.1010.11) and class Employee (Figs. 10.1210.13) to demonstrate objects as members of other objects. The definition of class Employee (Fig. 10.12) contains private data members firstName, lastName, birthDate and hireDate. Members birthDate and hireDate are const objects of class Date, which contains private data members month, day and year. The Employee constructor's header (Fig. 10.13, lines 1821) specifies that the constructor receives four parameters (first, last, dateOfBirth and dateOfHire). The first two parameters are used in the constructor's body to initialize the character arrays firstName and lastName. The last two parameters are passed via member initializers to the constructor for class Date. The colon (:) in the header separates the member initializers from the parameter list. The member initializers specify the Employee constructor parameters being passed to the constructors of the member Date objects. Parameter dateOfBirth is passed to object birthDate's constructor (Fig. 10.13, line 20), and parameter dateOfHire is passed to object hireDate's constructor (Fig. 10.13, line 21). Again, member initializers are separated by commas. As you study class Date (Fig. 10.10), notice that the class does not provide a constructor that receives a parameter of type Date. So, how is the member initializer list in class Employee's constructor able to initialize the birthDate and hireDate objects by passing Date object's to their Date constructors? As we mentioned in Chapter 9, the compiler provides each class with a default copy constructor that copies each member of the constructor's argument object into the corresponding member of the object being initialized. Chapter 11 discusses how programmers can define customized copy constructors.

Figure 10.10. Date class definition.

 1  // Fig. 10.10: Date.h
 2  // Date class definition; Member functions defined in Date.cpp
 3  #ifndef DATE_H
 4  #define DATE_H
 5
 6  class Date
 7  {
 8  public:
 9     Date( int = 1, int = 1, int = 1900 ); // default constructor
10     void print() const; // print date in month/day/year format
11     ~Date(); // provided to confirm destruction order
12  private:
13     int month; // 1-12 (January-December)
14     int day; // 1-31 based on month
15     int year; // any year
16
17     // utility function to check if day is proper for month and year
18     int checkDay( int ) const;
19  }; // end class Date
20
21  #endif
Figure 10.11. Date class member-function definitions.
(This item is displayed on pages 536 - 537 in the print version)

 1  // Fig. 10.11: Date.cpp
 2  // Member-function definitions for class Date.
 3  #include <iostream>
 4  using std::cout;
 5  using std::endl;
 6
 7  #include "Date.h" // include Date class definition
 8
 9  // constructor confirms proper value for month; calls
10  // utility function checkDay to confirm proper value for day
11  Date::Date( int mn, int dy, int yr )
12  {
13     if ( mn > 0 && mn <= 12 ) // validate the month
14        month = mn;
15     else
16     {
17        month = 1; // invalid month set to 1
18        cout << "Invalid month (" << mn << ") set to 1.\n";
19     } // end else
20
21     year = yr; // could validate yr
22     day = checkDay( dy ); // validate the day
23
24     // output Date object to show when its constructor is called
25     cout << "Date object constructor for date ";
26     print();
27     cout << endl;
28  } // end Date constructor
29 
30  // print Date object in form month/day/year
31  void Date::print() const
32  {
33     cout << month << '/' << day << '/' << year;
34  } // end function print
35 
36  // output Date object to show when its destructor is called
37  Date::~Date()
38  {
39     cout << "Date object destructor for date ";
40     print();
41     cout << endl;
42  } // end ~Date destructor
43 
44  // utility function to confirm proper day value based on
45  // month and year; handles leap years, too
46  int Date::checkDay( int testDay ) const
47  {
48     static const int daysPerMonth[ 13 ] =
49        { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
50 
51  // determine whether testDay is valid for specified month
52  if ( testDay > 0 && testDay <= daysPerMonth[ month ] )
53     return testDay;
54 
55  // February 29 check for leap year
56  if ( month == 2 && testDay == 29 && ( year % 400 == 0 ||
57     ( year % 4 == 0 && year % 100 != 0 ) ) )
58     return testDay;
59 
60     cout << "Invalid day (" << testDay << ") set to 1.\n";
61     return 1; // leave object in consistent state if bad value
62  } // end function checkDay
Figure 10.12. Employee class definition showing composition.
(This item is displayed on page 537 in the print version)

 1  // Fig. 10.12: Employee.h
 2  // Employee class definition.
 3  // Member functions defined in Employee.cpp.
 4  #ifndef EMPLOYEE_H
 5  #define EMPLOYEE_H
 6
 7  #include "Date.h" // include Date class definition
 8
 9  class Employee
10  {
11  public:
12     Employee( const char * const, const char * const,
13        const Date &, const Date & );
14     void print() const;
15     ~Employee(); // provided to confirm destruction order
16  private:
17     char firstName[ 25 ];
18     char lastName[ 25 ];
19     const Date birthDate; // composition: member object
20     const Date hireDate; // composition: member object
21  }; // end class Employee
22
23  #endif
Figure 10.13. Employee class member-function definitions, including constructor with a member initializer list.
(This item is displayed on pages 538 - 539 in the print version)

 1  // Fig. 10.13: Employee.cpp
 2  // Member-function definitions for class Employee.
 3  #include <iostream>
 4  using std::cout;
 5  using std::endl;
 6
 7  #include <cstring> // strlen and strncpy prototypes
 8  using std::strlen;
 9  using std::strncpy;
10
11  #include "Employee.h" // Employee class definition
12  #include "Date.h" // Date class definition
13
14  // constructor uses member initializer list to pass initializer
15  // values to constructors of member objects birthDate and hireDate
16  // [Note: This invokes the so-called "default copy constructor" which the
17  // C++ compiler provides implicitly.]
18  Employee::Employee( const char * const first, const char * const last,
19     const Date &dateOfBirth, const Date &dateOfHire )
20     : birthDate( dateOfBirth ), // initialize birthDate
21       hireDate( dateOfHire ) // initialize hireDate
22  {
23     // copy first into firstName and be sure that it fits
24     int length = strlen( first );
25     length = ( length < 25 ? length : 24 );
26     strncpy( firstName, first, length );
27     firstName[ length ] = '\0';
28
29     // copy last into lastName and be sure that it fits
30     length = strlen( last );
31     length = ( length < 25 ? length : 24 );
32     strncpy( lastName, last, length );
33     lastName[ length ] = '\0';
34
35     // output Employee object to show when constructor is called
36     cout << "Employee object constructor: "
37        << firstName << ' ' << lastName << endl;
38  } // end Employee constructor
39
40  // print Employee object
41  void Employee::print() const
42  {
43     cout << lastName << ", " << firstName << " Hired: ";
44     hireDate.print();
45     cout << " Birthday: ";
46     birthDate.print();
47     cout << endl;
48  } // end function print
49
50  // output Employee object to show when its destructor is called
51  Employee::~Employee()
52  {
53     cout << "Employee object destructor: "
54        << lastName << ", " << firstName << endl;
55  } // end ~Employee destructor

[Page 536]

Figure 10.14 creates two Date objects (lines 1112) and passes them as arguments to the constructor of the Employee object created in line 13. Line 16 outputs the Employee object's data. When each Date object is created in lines 1112, the Date constructor defined at lines 1128 of Fig. 10.11 displays a line of output to show that the constructor was called (see the first two lines of the sample output). [Note: Line 13 of Fig. 10.14 causes two additional Date constructor calls that do not appear in the program's output. When each of the Employee's Date member object's is initialized in the Employee constructor's member initializer list, the default copy constructor for class Date is called. This constructor is defined implicitly by the compiler and does not contain any output statements to demonstrate when it is called. We discuss copy constructors and default copy constructors in detail in Chapter 11.]


[Page 539]

Figure 10.14. Member-object initializers.

 1  // Fig. 10.14: fig10_14.cpp
 2  // Demonstrating composition--an object with member objects.
 3  #include <iostream>
 4  using std::cout;
 5  using std::endl;
 6
 7  #include "Employee.h" // Employee class definition
 8
 9  int main()
10  {
11     Date birth( 7, 24, 1949 );
12     Date hire( 3, 12, 1988 );
13     Employee manager( "Bob", "Blue", birth, hire );
14
15     cout << endl;
16     manager.print();
17
18     cout << "\nTest Date constructor with invalid values:\n";
19     Date lastDayOff( 14, 35, 1994 ); // invalid month and day
20     cout << endl;
21     return 0;
22  } // end main

 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

 Test Date constructor with invalid values:
 Invalid month (14) set to 1.
 Invalid day (35) set to 1.
 Date object constructor for date 1/1/1994

 Date object destructor for date 1/1/1994
 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


Class Date and class Employee each include a destructor (lines 3742 of Fig. 10.11 and lines 5155 of Fig. 10.13, respectively) that prints a message when an object of its class is destroyed. This enables us to confirm in the program output that objects are constructed from the inside out and destroyed in the reverse order from the outside in (i.e., the Date member objects are destroyed after the Employee object that contains them). Notice the last four lines in the output of Fig. 10.14. The last two lines are the outputs of the Date destructor running on Date objects hire (line 12) and birth (line 11), respectively. These outputs confirm that the three objects created in main are destructed in the reverse of the order in which they were constructed. (The Employee destructor output is five lines from the bottom.) The fourth and third lines from the bottom of the output window show the destructors running for the Employee's member objects hireDate (Fig. 10.12, line 20) and birthDate (Fig. 10.12, line 19). These outputs confirm that the Employee object is destructed from the outside ini.e., the Employee destructor runs first (output shown five lines from the bottom of the output window), then the member objects are destructed in the reverse order from which they were constructed. Again, the outputs in Fig. 10.14 did not show the constructors running for these objects, because these were the default copy constructors provided by the C++ compiler.


[Page 540]

A member object does not need to be initialized explicitly through a member initializer. If a member initializer is not provided, the member object's default constructor will be called implicitly. Values, if any, established by the default constructor can be overridden by set functions. However, for complex initialization, this approach may require significant additional work and time.

Common Programming Error 10.6

A compilation error occurs if a member object is not initialized with a member initializer and the member object's class does not provide a default constructor (i.e., the member object's class defines one or more constructors, but none is a default constructor).


Performance Tip 10.2

Initialize member objects explicitly through member initializers. This eliminates the overhead of "doubly initializing" member objectsonce when the member object's default constructor is called and again when set functions are called in the constructor body (or later) to initialize the member object.


Software Engineering Observation 10.6

If a class member is an object of another class, making that member object public does not violate the encapsulation and hiding of that member object's private members. However, it does violate the encapsulation and hiding of the containing class's implementation, so member objects of class types should still be private, like all other data members.


In line 26 of Fig. 10.11, notice the call to Date member function print. Many member functions of classes in C++ require no arguments. This is because each member function contains an implicit handle (in the form of a pointer) to the object on which it operates. We discuss the implicit pointer, which is represented by keyword this, in Section 10.5.

Class Employee uses two 25-character arrays (Fig. 10.12, lines 1718) to represent the first name and last name of the Employee. These arrays may waste space for names shorter than 24 characters. (Remember, one character in each array is for the terminating null character, '\0', of the string.) Also, names longer than 24 characters must be truncated to fit in these fixed-size character arrays. Section 10.7 presents another version of class Employee that dynamically creates the exact amount of space required to hold the first and the last name.


[Page 541]

Note that the simplest way to represent an Employee's first and last name using the exact amount of space required is to use two string objects (C++ Standard Library class string was introduced in Chapter 3). If we did this, the Employee constructor would appear as follows

 Employee::Employee( const string &first, const string &last,
    const Date &dateOfBirth, const Date &dateOfHire )
    : firstName( first), // initialize firstName
      lastName( last ), // initialize lastName
      birthDate( dateOfBirth ), // initialize birthDate
      hireDate( dateOfHire ) // initialize hireDate
 {
    // output Employee object to show when constructor is called
    cout << "Employee object constructor: "
       << firstName << ' ' << lastName << endl;
 }  // end Employee constructor

Notice that data members firstName and lastName (now string objects) are initialized through member initializers. The Employee classes presented in Chapters 1213 use string objects in this fashion. In this chapter, we use pointer-based strings to provide the reader with additional exposure to pointer manipulation.


Previous Page
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
【7层】6900平米左右一字型框架办公楼毕业设计(建筑结构图、计算书) 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值