C++的一點基本自我修養(二)--拷貝建構函式

兔美醬xz發表於2014-03-26

拷貝建構函式

         在C++中,除了可以使用建構函式直接建立一個新的物件之外,有時還需要根據已經存在的某個物件建立一個新的物件作為這個物件的副本。

         在大多數情況下,預設的拷貝建構函式已經能夠滿足我們的需要了,但是有的時候,特別是類當中有指標型別的屬性的時候,以拷貝記憶體形式實現的預設拷貝建構函式只能複製指標屬性的值,而不能複製指標屬性所指向的記憶體,在這種情況下,就需要自己定義類的拷貝建構函式,完成指標屬性等需要特殊處理的屬性的拷貝工作。例如,有一個Computer類,它有一個指標型別的屬性m_pKeyboard指向它所連線的鍵盤。

#include <iostream>
#include <string>
#include <cassert>
using namespace std;

//鍵盤類
struct Keyboard 
{
	//鍵盤型號
	string m_strModel;
};

//定義了拷貝建構函式的電腦類
class Computer
{
public :
	//預設建構函式
	Computer()
		: m_pKeyboard(NULL)
	{}
	//拷貝建構函式,引數是const修飾的Computer類的引用
	Computer(const Computer& com)
		: m_strModel(com.m_strModel) //物件型別的成員屬性直接使用初始化列表
									 //完成拷貝
	{
		// 獲得已有物件com的指標屬性m_pKeyborad並賦值給pOldKeyboard
		Keyboard* pOldKeyboard = com.GetKeyboard();
		//以pOldKeyboard指向的Keyboard物件為藍本,
		//建立一個新的Keyboard類物件賦值給m_Keyboard屬性
		if (NULL != pOldKeyboard)
		m_pKeyboard = new Keyboard(*(pOldKeyboard));
		else
		m_pKeyboard = NULL;
	}
	
	//省略解構函式
	
	//成員函式
	void SetKeyboard(Keyboard* pKeyboard)
	{
		m_pKeyboard = pKeyboard;
	}
	Keyboard* GetKeyboard() const
	{
		return m_pKeyboard;
	}

private:
	// 指標型別的成員屬性
	Keyboard* m_pKeyboard;
	// 物件型別的成員屬性
	string m_strModel;
};

在這段程式碼中,我們為Computer類建立了一個自定義拷貝建構函式。在這個拷貝建構函式中,針對物件型別的成員屬性,我們直接使用初始化列表就完成了屬性的拷貝。而針對指標型別成員屬性m_pKeyboard的拷貝,並不能直接採用記憶體拷貝的形式完成,那樣只是拷貝了指標的值,而指標所指向的內容並沒有得到拷貝。要完成指標型別成員屬性的拷貝,首先應該獲得已有物件的m_pKeyboard屬性,也就是獲得它所指向的Keyboard物件,然後以這個Keyboard物件為藍本,利用Keyboard類的預設拷貝建構函式建立這個Keyboard物件的一個副本,最後將其地址賦值給m_pKeyboard屬性,這樣,這個拷貝建構函式不僅能夠拷貝Computer類的物件型別成員屬性m_strModel,也能夠正確地完成指標型別成員屬性m_pKeyboard的拷貝,最終才能完成Computer類的拷貝。

主函式程式碼:

#include "myHeader.h"


int main()
{
	//建立一個Computer物件oldcom
	Computer oldcom;
	//建立oldcom的Keyboard物件並修改其屬性
	Keyboard keyboard;
	keyboard.m_strModel = "Microsoft-101";
	oldcom.SetKeyboard(&keyboard);
	//利用Computer類的拷貝建構函式建立新物件newcom
	//新的newcom物件是oldcom物件的一個副本
	Computer newcom(oldcom);

	//使用斷言assert()判斷兩個Computer物件的m_pKeyboard屬性不同,
	//也就是它們分別指向兩個不同的Keyboard物件,
	//但是,這兩個Keyboard物件的屬性卻是相同的
	assert(newcom.GetKeyboard()!=oldcom.GetKeyboard());
	assert(newcom.GetKeyboard()->m_strModel!=oldcom.GetKeyboard()->m_strModel);
	return 0;
}



相關文章