1。调用默认构造函数
例如,下面的程序定义了学号类和学生类,学生类中包含有学号类:
//***********************
//** ch12_10.cpp **
//***********************
#i nclude <iostream.h>
#i nclude <string.h>
int nextStudentID=0;
class StudentID{
public:
StudentID()
{
value=++nextStudentID;
cout <<"Assigning student id " <<value <<endl;
}
~StudentID()
{
--nextStudentID;
cout <<"Destructing id " <<value <<endl;
}
protected:
int value;
};
class Student{
public:
Student(char* pName="noName")
{
cout <<"Constructing student " <<pName <<endl;
strncpy(name,pName,sizeof(name));
name[sizeof(name)-1]='\0';
}
protected:
char name[20];
StudentID id;
};
void main()
{
Student s("Randy");
}
运行结果为:
Assigning student id 1
Constructing student Randy
Destructing id 1
当学生类对象被构造时,一个学号赋予了该学生对象。
学号类StudentlD含有保护数据成员value,按规定不能被另一个类Student的类对象访问,即使Student类包含StudentlD类。
Student类包含一个成员id,id属于StudentID类,Student构造函数不能访问id对象中的保护数据成员。所以,在Student类对象构造时,须调用StudentID类的构造函数来初始化id。这就是类与类之间“互不干涉内政”的严酷关系。
“Students("Randy");”语句执行步骤如下:
(1)分配s对象空间,调用Student构造函数。
(2)建立s对象空间中的结构,第一为name[20],第二为id,因它属于StudentID类,所以调用StudentID的构造函数,这时,id的保护数据value得到了赋值,全局变量nextStudentID得到了赋值,并且输出第一行信息。之后,返回到Student构造函数。
(3)执行Student构造函数体。输出第二行信息,数据成员name得到了赋值。之后返回到主函数main()。
如果Student类未定义构造函数,C++提供的默认构造函数将自动地为各个数据成员(如果是类对象的话)调用构造函数。程序结束时也与此相同。类的析构函数将自动地为各个具有析构函数的数据成员调用析构函数。
我们看到,上面的例子中,Student构造函数调用了StudentID的默认构造函数。但如果想调用的构造函数不是默认构造函数,那又如何呢?
2。有参数的情况:
程序基本不变:
Student(char* pName="noName",int ssID=0)
{
cout <<"Constructing student " <<pName <<endl;
strncpy(name,pName,sizeof(name));
name[sizeof(name)-1]='\0';
StudentID id(ssID); //希望将学号传给学号类对象(有点修改)
}
StudentID的构造函数改为从参数中接受一个学号值。在Student构造函数内部,增加了一条语句“StudentID id(ssID);”,企图将ssID参数值传给数据成员id但实际上,在Student构造函数中构造了一个名为id的StudentID局部对象。由于是局部对象,所以,当Student构造函数返回时,便析构了这个对象。
那么,能否像下面这样在Student类中直接给id对象初始化呢?
class Student
{
public:
Student(char* pName="noName",int ssID);
protected:
char name[20];
StudentID id(9818);
//error:类定义是不分配空间和初始化的。
};
“StudentID id(9818);”是创建对象语句,而不是类定义中允许的声明数据成员形式
“StudentlD id=9818;”或者“StudentID id(ssID);” 也都是不允许的。前者就是“StudentID id(9818);”后者ssID成了参数,类定义是不会调用构造函数的。因为类是一个抽象的概念,并不是一个实体,并不含有属性值,而只有对象才占有一定的空间,含有明确的属性值。我们只能按照格式“类型标识符;”去声明类的数据成员。
3。总结:
主程序不变:修改如下
Student(char* pName="noName",int ssID=0):id(ssID)
{
cout <<"Constructing student " <<pName <<endl;
strncpy(name,pName,sizeof(name));
name[sizeof(name)-1]='\0';
}
冒号表示后面要对类的数据成员的构造函数进行调用。SSID可以是Student构造函数的形参,id(ssID)表示调用以ssID为实参的Student构造函数。
上例中,Student构造函数头冒号后面如果是id()的形式,表示调用Student的默认构造函数,并且可以省略。