包含对象成员的类的构造函数
C++中允许将一个已定义的类对象作为另一个类的数据成员,即类中的数据成员可以是其他类的对象,称这种成员是类的子对象或成员对象。
在类中包含对象成员,能够更真实地描述现实世界中事物之间的包含关系,比如可以先定义日期类描述年月日信息,再定义学生类时需要用日期描述学生的生日,则可以使用日期类的对象作为学生类的成员。
把某个类对象作为新类成员时,新类的定义形式如下所示:
class 新类名
{
类名1 成员1;
类名2 成员2;
…
};
从上述形式看出,定义成员对象和定义普通数据成员的方法一致,都是“类名+变量名”,另外成员1、成员2所属的类应该是已经定义好的类。
下面定义学生类Student,包含成员对象m_iBirthday,该成员属于日期类Date,代码如下所示:
class Date //日期类定义
{
private:
int m_nYear, m_nMonth, m_nDay;
};
class Student //定义学生类
{
private:
Date m_iBirthday; //Date类型的数据成员
char m_gName[20];
int m_nID;
};
上述代码中,Student类中m_iBirthday是Date类对象,该对象也称为Student类中的成员对象。
若类X中有成员对象,则创建X类对象时,先执行成员对象的构造函数,初始化成员对象,再执行类X的构造函数初始化其他非对象成员。并且,若类X的成员对象的构造函数带有参数,则定义X类的构造函数时,应使用初始化表的形式对成员对象进行初始化,具体形式如下所示:
class X //定义X类
{
public:
X(参数表);
private:
类型1 成员1; //成员对象1
类型2 成员2; //成员对象2
…
};
//X构造函数,使用初始化表对成员对象初始化
X::X(参数表):成员1(参数表1),成员2(参数表2),…
{
构造函数体
}
接下来通过一个案例来学习使用初始化表对类中对象成员完成初始化的方法,如例1所示。
例1
1 #include <iostream>
2 #include <cstring>
3 using namespace std;
4
5 class Date //定义日期类
6 {
7 public:
8 Date(int y, int m, int d); //声明带参数的构造函数
9 void show();
10 private:
11 int m_nYear, m_nMonth, m_nDay;
12 };
13 Date::Date(int y, int m, int d) //定义Date类的构造函数
14 {
15 cout << "Date constructor!" << endl;
16 m_nYear = y;
17 m_nMonth = m;
18 m_nDay = d;
19 }
20 void Date::show() //定义成员函数show(),显示日期
21 {
22 cout << m_nYear << "-" << m_nMonth << "-" << m_nDay << endl;
23 }
24 class Student //定义学生类
25 {
26 public:
27 //声明带参数的构造函数,con_name表示学生姓名,con_id表示学生id,y、m、d表示日期信息
28 Student(char *con_name, int con_id, int y, int m, int d);
29 void disp_msg();
30 private:
31 Date m_iBirthday; //Date类型的数据成员
32 char m_gName[20];
33 int m_nID;
34 };
35 //定义Student类带参数的构造函数,参数y、m、d用于对Date类对象m_iBirthday初始化
36 Student::Student(char *con_name, int con_id,
37 int y, int m, int d):m_iBirthday(y, m, d)
38 {
39 cout << "Student constructor!" << endl;
40 strcpy_s(m_gName, strlen(con_name) + 1, con_name);
41 m_nID = con_id;
42 }
43 void Student::disp_msg() //定义成员函数disp_msg(),显示学生信息
44 {
45 cout << "std name:" << m_gName << ", id = " << m_nID << ", birthday:";
46 m_iBirthday.show();
47 }
48 int main()
49 {
50 Student student("xiaoming", 1, 1998, 10, 25); //调用带参数的构造函数定义类对象
51 student.disp_msg();
52 system("pause");
53 return 0;
54 }
运行结果如图1所示。
图1 例1运行结果
例1中Student类中带参数的构造函数通过初始化表对m_iBirthday成员对象进行初始化,如代码第36-37行。代码第50行,在main()函数中定义类对象时提供了5个参数,最后的三个参数表示学生的出生日期,这个信息将记录在m_iBirthday成员对象中。从运行结果看出,初始化Student类对象时先调用成员对象m_iBirthday的构造函数,然后再调用Student类的构造函数。
也可以定义Date类的拷贝构造函数,再定义一个Student的重载构造函数,函数形式如下所示:
Student(char *con_name, int con_id, Date &con_birthday):m_iBirthday(con_birthday)
{
cout << "Student constructor!" << endl;
strcpy_s(m_gName, strlen(con_name) + 1, con_name);
m_nID = con_id;
}
在主函数中定义Date类对象,将该对象作为构造函数参数用于初始化m_iBirthday成员,代码如下所示:
//main()函数中内容
Date date(1998, 10, 25);
Student student("xiaoming", 1, date);
拷贝构造函数的内容将在后面小节介绍,初学者可先自行学习,尝试实现本例要求。