C++知識點49——類繼承與類的構造、拷貝、operator=和解構函式

Master Cui發表於2020-11-21

一、類繼承與建構函式

在C++中,無論類是否有繼承關係,每個類各自控制它自己的成員的初始化。子類雖然含有基類的成員,但是並不能對基類的成員直接初始化,需要使用基類的建構函式初始化子類中的基類部分。

從語法上說,可以在子類的建構函式的函式體中給基類的protected或public成員賦值,但是最好不要這樣做

子類初始化時,會先呼叫基類的建構函式,初始化基類的部分並,然後按照子類成員在類中的宣告順序逐個初始化子類部分

示例

class base
{
public:
	base():
	bpub(0),
	bpro(0),
	bpri(0)
	{
		cout<<__func__<<endl;
	}

	base(int init):
	bpub(0),
	bpro(0),
	bpri(0)
	{
		cout<<"base(int init)"<<endl;
	}

	~base(){cout<<__func__<<endl;}
	int bpub; 

protected:
	int bpro;

private:
	int bpri;
	
};

class derive:public base
{
public:
	derive(){cout<<__func__<<endl;}
	~derive(){cout<<__func__<<endl;}
	int dpub; 

protected:
	int dpro;

private:
	int dpri;
	
};

class derive2:public base
{
public:
	derive2():
	base(),
	d2pub(-1),
	d2pro(-1),
	d2pri(-1)
	{
		cout<<__func__<<endl;
	}

	derive2(int init):
	base(init),
	d2pub(-1),
	d2pro(-1),
	d2pri(-1)
	{
		cout<<"derive2(int init)"<<endl;
	}

	~derive2() 
	{
		cout<<__func__<<endl;
	}

	int d2pub; 

protected:
	int d2pro;

private:
	int d2pri;
};

int main(int argc, char const *argv[])
{
	derive d;
	derive2 d21;
	derive2 d22(10);
	return 0;
}

上述程式碼演示瞭如何在子類的建構函式中顯示指定要呼叫基類的建構函式

輸出結果表示:

1、就算在子類的建構函式中不顯式指定呼叫基類的建構函式,當建立子類物件(derive)時,會先呼叫基類的預設建構函式並對基類部分進行預設初始化。

2、定義類時,可以將子類建構函式的形參傳給基類的建構函式

 

二、類繼承與拷貝建構函式

如果想在拷貝子類物件時,對基類的成員也進行拷貝,需要在子類的拷貝建構函式的初始化列表中顯示呼叫基類的拷貝建構函式。如果不顯示定義基類的拷貝建構函式,那麼在對子類進行拷貝構造操作時,會先呼叫基類的建構函式

示例

class base2
{
public:
	base2(){cout<<__func__<<endl;}
	base2(const base2 &b2):memb(b2.memb){cout<<"base2(const base2 &b2)"<<endl;}
	~base2(){cout<<__func__<<endl;}
	int memb;
};

class derive2:public base2
{
public:
	derive2(){cout<<__func__<<endl;}
	~derive2(){cout<<__func__<<endl;}
	derive2(const derive2 &d2)
	:base2(d2), memd(d2.memd) {cout<<"derive2(const derive2 &d2)"<<endl;}
	int memd;
};

int main(int argc, char const *argv[])
{
	derive2 d2;
	derive2 b2t=d2;
	return 0;
}

如果想在拷貝子類物件時,對基類的成員也進行拷貝,需要在子類的拷貝建構函式的初始化列表中顯示呼叫基類的拷貝建構函式。這樣,當對一個子類進行拷貝初始化時,也會先呼叫基類的拷貝建構函式,對子類中的基類部分進行拷貝初始化,然後再呼叫子類的拷貝建構函式進行對子類部分進行拷貝初始化

如果不顯示定義基類的拷貝建構函式,那麼在對子類進行拷貝構造操作時,會先呼叫基類的建構函式,將上述程式碼中的第5行註釋掉的輸出結果如下

所以,如果要定義子類的拷貝建構函式,請在子類的拷貝建構函式的初始化列表中顯示呼叫基類的拷貝建構函式,然後再對子類的成員進行初始化

 

三、類繼承與operator=

和拷貝建構函式一樣,子類的operator=必須顯示呼叫基類的operator=

示例

在拷貝建構函式的示例程式碼中分別新增基類和子類的operator=

class base2
{
public:
	//....
	base2 &operator=(const base2 &b2)
	{
		memb=b2.memb;
		return *this;
	}
	int memb;
};

class derive2:public base2
{
public:
	//....
	derive2 &operator=(const derive2 &d2)
	{
		base2::operator=(d2);
		memd=d2.memd;
		return *this;
	}
	int memd;
};

int main(int argc, char const *argv[])
{
	derive2 d2;
	derive2 b2t;
	b2t=d2;
	return 0;
}

如果不顯示呼叫基類的operator=,那麼子類物件的基類部分將不會被賦值

 

四、類繼承與解構函式

根據上面的輸出結果可以知道,物件銷燬的順序和物件建立的順序是相反的,一個子類物件銷燬時,會先執行子類的解構函式,然後是基類的解構函式,以此類推,直至最上面的基類

雖然子類物件被釋放時,會分別呼叫子類和基類的解構函式,但是,子類的解構函式只負責釋放子類的成員所佔有的資源,子類中對應的基類部分由基類的解構函式進行釋放

 

參考

《C++ Primer》

 

歡迎大家評論交流,作者水平有限,如有錯誤,歡迎指出

相關文章