C++子類對象—子類對象的構造和析構
2020-05-23 14:25:31
供稿:網友
對象在使用之前,始終是要經歷“構造”這個過程的。在第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...
根據運行結果,我們可以確認:使用了繼承之后,析構函數的運行順序依然恰好與構造函數的運行順序相反。