对象在使用之前,始终是要经历“构造”这个过程的。在第15章,我们了解到当一个对象的成员数据是另一个对象的时候,就先运行成员对象的构造函数,再运行父对象的构造函数。但是继承的出现,会引入子类的构造函数。这时候,这些构造函数的运行顺序又是怎样的呢?
讨论子类对象的构造,就是在讨论子类对象的生成方式。它是先生成父类对象的成员,再对其进行扩展呢,还是先生成子类对象的成员,然后再对其进行补充?我们还是修改一下程序17.3.2,用事实来解决这个问题:(程序17.4.1)
//node.h和linklist.h同程序17.3.2
//stack.h
- #include "linklist.h"
- class Stack:private Linklist//私有继承链表类
- {
- public:
- bool push(int i,char c);
- bool pop(int &i,char &c);
- void show();
- Stack(int i,char c);
- Stack();
- };
- Stack::Stack(int i,char c):Linklist(i,c)//将子类构造函数的参数传递给父类的构造函数
- {
- cout <<"Stack constructor with parameter is running..." <<endl;
- }
- Stack::Stack()//子类构造函数
- {
- cout <<"Stack constructor is running..." <<endl;
- }
- bool Stack::push(int i,char c)
- {
- while (pcurrent->next!=NULL)
- pcurrent=pcurrent->next;
- return Insert(i,c);
- }
- bool Stack::pop(int &i,char &c)
- {
- while (pcurrent->next!=NULL)
- pcurrent=pcurrent->next;
- i=pcurrent->idata;
- c=pcurrent->cdata;
- return Delete();
- }
- void Stack::show()
- {
- Show();
- }
//main.cpp
- #include <iostream>
- #include "stack.h"
- int main()
- {
- Stack ss(1,'4');//调用带参数的构造函数
- cout <<"Stack ss constructed" <<endl;
- ss.show();
- Stack zz; //调用不带参数的构造函数
- cout <<"Stack zz constructed" <<endl;
- zz.show();
- return 0;
- }
运行结果:
Node constructor is running...
Linklist constructor is running...
Stack constructor with parameter is running...
Stack ss constructed
1 4
Node constructor is running...
Linklist constructor is running...
Stack constructor is running...
Stack zz constructed
0 0
Linklist destructor is running...
Node destructor is running...
Linklist destructor is running...
Node destructor is running...
这个程序中有三个类,其中Stack类是Linklist类的子类,Node类的对象是Linklist类的成员数据。根据程序的运行结果,我们可以确定,父类的成员对象仍然是最先构造的,接着是运行父类的构造函数,最后运行子类的构造函数。也就是说子类对象是在父类对象的基础上扩展而成的。
另外,如果我们希望把子类的构造函数的参数传递给父类的构造函数时,可以在子类的构造函数定义中用以下格式调用父类的构造函数:
子类名::构造函数名(参数表):父类名(参数表)
如程序17.4.1就是用上述方法实现子类和父类的构造函数参数传递。这样的方法不仅使子类对象的初始化变得简单,并且使子类和父类的构造函数分工明确,易于维护。
在第15章中介绍析构函数的时候,我们就说它的运行顺序往往是和构造函数的运行顺序相反的。那么使用了继承之后,是否依然是这样的规律呢?我们继续修改程序17.4.1,尝试验证我们的猜想。
//node.h和linklist.h同程序17.3.2
//stack.h
- #include "linklist.h"
- class Stack:private Linklist
- {
- public:
- bool push(int i,char c);
- bool pop(int &i,char &c);
- void show();
- Stack(int i,char c);
- Stack();
- ~Stack();//析构函数
- };
- Stack::Stack(int i,char c):Linklist(i,c)
- {
- cout <<"Stack constructor with parameter is running..." <<endl;
- }
- Stack::Stack()
- {
- cout <<"Stack constructor is running..." <<endl;
- }
- Stack::~Stack()
- {
- cout <<"Stack destructor is running..." <<endl;
- }
- bool Stack::push(int i,char c)
- {
- while (pcurrent->next!=NULL)
- pcurrent=pcurrent->next;
- return Insert(i,c);
- }
- bool Stack::pop(int &i,char &c)
- {
- while (pcurrent->next!=NULL)
- pcurrent=pcurrent->next;
- i=pcurrent->idata;
- c=pcurrent->cdata;
- return Delete();
- }
- void Stack::show()
- {
- Show();
- }
//main.cpp
- #include <iostream>
- #include "stack.h"
- int main()
- {
- Stack zz;
- cout <<"Stack zz constructed" <<endl;
- zz.show();
- return 0;
- }
运行结果:
Node constructor is running...
Linklist constructor is running...
Stack constructor is running...
Stack zz constructed
0 0
Stack destructor is running...
Linklist destructor is running...
Node destructor is running...
根据运行结果,我们可以确认:使用了继承之后,析构函数的运行顺序依然恰好与构造函数的运行顺序相反。