一个类的对象作为另一个类的数据成员
如果一个类A的对象作为另一个类B的数据成员,则在类B的对象创建过程中,调用其构造函数的过程中,数据成员(类A的对象)会自动调用类A的构造函数。
但应注意:如果类A的构造函数为有参函数时,则在程序中必须在类B的构造函数的括号后面加一“:”和被调用的类A的构造函数,且调用类A的构造函数时的实参值必须来自类B的形参表中的形参。这种方法称为初始化表的方式调用构造函数。如:以上面定义的类X为例,在对类X的对象进行初始化时,必须首先初始化其中的子对象,即必须首先调用这些子对象的构造函数。因此,类X的构造函数的定义格式应为:
X::X(参数表0):成员1(参数表1),成员2(参数表2),…,成员n(参数表n)
{ ……}
其中,参数表1提供初始化成员1所需的参数,参数表2提供初始化成员2所需的参数,依此类推。并且这几个参数表的中的参数均来自参数表0,另外,初始化X的非对象成员所需的参数,也由参数表0提供。
在构造新类的对象过程中,系统首先调用其子对象的构造函数,初始化子对象;然后才执行类X自己的构造函数,初始化类中的非对象成员。对于同一类中的不同子对象,系统按照它们在类中的说明顺序调用相应的构造函数进行初始化,而不是按照初始化表的顺序。
试分析以下程序的执行结果:
#include <iostream.h>
#include <string.h>
class Student
{ public:
Student(char *pName="No name")
{ cout<<"构造新同学:"<<pName<<endl;
strncpy(name,pName,sizeof(name));
name[sizeof(name)-1]='\0';
}
Student(Student &s)
{ cout<<"构造copy of "<<s.name<<endl;
strcpy(name, " copy of ");
strcat(name,s.name);
}
~Student()
{ cout<<"析构 "<<name<<endl; }
protected:
char name[40]; };
class Tutor
{ public:
Tutor(Student &s):student(s)//此为初始化表,调用
//Student的拷贝构造函数
{ cout<<"构造指导教师 \n"; }
protected:
Student student;
};
void main()
{ Student st1; //此处调用Student的构造函数Student(char
*pName="No name")
Student st2("zhang"); //同上
Tutor tutor(st2); //此处调用Tutor的构造函数Tutor(Student &s)
//在构造tutor对象的过程中,用初始化表调用
//Student类的拷贝构造函数Student(Student &s)
}
执行结果如下:
构造新同学:No name
构造新同学:zhang
构造copy of zhang
构造指导教师
析构 copy of zhang
析构 zhang
析构 No name