1. 程式人生 > >繼承和派生(2):析構和構造

繼承和派生(2):析構和構造

一、建構函式

     派生類的物件的資料結構是由基類中說明的資料成員和派生類中說明的資料成員共同構成。 將派生類的物件中由基類中說明的資料成員和操作所構成的封裝體稱為基類子物件,它由基類中的建構函式進行初始化。

     建構函式不能夠被繼承,因此,派生類的構 造函式必須通過呼叫基類的建構函式來初始化基 類子物件。所以,在定義派生類的建構函式時除 了對自己的資料成員進行初始化外,還必須負責 呼叫基類建構函式使基類資料成員得以初始化。 如果派生類中還有子物件時,還應包含對子物件 初始化的建構函式。

注意:建構函式的呼叫順序:先祖先(基類) ,再客人(成員對 象),後自己(派生類) 。

案例一:

#include <iostream>
using namespace std;
class A
{ public:
    A(){a=0; cout<<"A's default constructor called."<<endl;}  //預設的建構函式
    A(int i){a=i; cout<<"A's constructor called."<<endl;}    //含引數的建構函式
    ~A(){cout<<"A's destructor called."<<endl;}            //解構函式
    void Print() const {cout<<a<<". ";}
    int Geta(){return a;}
private:
	int a;
};
class B:public A
{ public:
   B(){b=0; cout<<"B's default constructor called."<<endl;}
   B(int i, int j, int k);
  ~B(){cout<<"B's destructor called."<<endl;}
   void Print();
private:
	int b; A aa;
};

B::B(int i, int j, int k):A(i),aa(j)  //I初始化基類,j初始化子物件,k初始化B的資料成員b
{
	b=k;
cout<<"B's constructor called."<<endl;
}

void B::Print()
{ A::Print();
cout<<b<<". "<<aa.Geta()<<endl;
}

int main()
{
	B bb[2];
	//bb[0]=B(1,2,5); 
	//bb[1]=B(3,4,7);
	for(int i=0;i<2;i++)
		bb[i].Print();

	return 0;
}

執行結果:

                      

案例二:

#include <iostream>
using namespace std;
class A
{ public:
    A(){a=0; cout<<"A's default constructor called." <<"此時的a="<<a<<endl;}  //預設的建構函式
    A(int i){a=i; cout<<"A's constructor called." <<"此時的a="<<a<<endl;}    //含引數的建構函式
    ~A(){cout<<"A's destructor called." <<"此時的a="<<a<<endl;}            //解構函式
    void Print() const {cout<<a<<". ";}
    int Geta(){return a;}
private:
	int a;
};
class B:public A
{ public:
   B(){b=0; cout<<"B's default constructor called."<<"此時的b="<<b<<endl;}
   B(int i, int j, int k);
  ~B(){cout<<"B's destructor called." <<"此時的b="<<b<<endl;}
   void Print();
private:
	int b; A aa;
};

B::B(int i, int j, int k):A(i),aa(j)  //I初始化基類,j初始化子物件,k初始化B的資料成員b
{
	b=k;
cout<<"B's constructor called."<<endl;
}

void B::Print()
{ A::Print();
cout<<b<<". "<<aa.Geta()<<endl;
}

int main()
{
	B bb[2];
	bb[0]=B(1,2,5); 
	bb[1]=B(3,4,7);
	for(int i=0;i<2;i++)
		bb[i].Print();

	return 0;
}

執行結果:

 

二、解構函式

       當物件被刪除時,派生類的解構函式被執行。由於解構函式也不能被繼承,因此在執行派生類的解構函式時,基類的解構函式也將被呼叫。

        在派生類中是否定義解構函式與基類無關。若派生類物件在退出其作用域前,有資料需要做善後工 作,就需要定義解構函式。基類的解構函式不會因 派生類沒有解構函式而得不到執行,它們各自是 獨立的。 若基類、成員類、派生類都有解構函式, 則執行的順序是:先自己(派生類),再客人(成員 物件),後祖先(基類)。其順序與執行建構函式時 的順序正好相反。

參考例子:

#include <iostream> 
using namespace std;
class M 
{ public: 
    M(){m1=m2=0;}    
	M(int i,int j){m1=i;m2=j;}     
	void print(){cout<<m1<<", "<<m2<<", ";}     
	~M(){cout<<"M's destructor called."<<endl;}     
  private:        
	  int m1,m2; 
};
class N:public M 
{ public:     
   N(){n=0;}     
   N(int i, int j, int k);  
   void print()  
   { M::print(); cout<<n<<endl; }  
   ~N(){cout<<"N's destructor called"<<endl;}
  private:  
	int n; 
}; 

N::N(int i,int j,int k):M(i,j),n(k) {  }

int  main() 
{  
	N n1(5,6,7), n2(-2,-3,-4); 
	n1.print();  
	n2.print(); 
	return 0;
}

執行結果:

 派生類建構函式使用的注意事項

 1)派生類建構函式中可以省略對基類構造函 數的呼叫,其條件是在基類中必須有預設的 建構函式,或者根本沒有定義建構函式。  

 2)若基類建構函式有引數,則派生類必須定 義建構函式,提供將引數傳遞給基類構造函 數。   

 

《未完待續》