天天看點

函數傳值 複制構造函數 深度拷貝

class A{
	int *m_pi;
public:
	A()
	{
		m_pi = new int;
	}
	~A()
	{
		delete m_pi;
	}
};

void func(A _a)
{
	int a = 0;
}

void main()
{ 
	A a;
	func(a);
}      

運作後崩潰,原因是當調用func時,産生一個臨時對象,并未調用構造函數,調用預設的位拷貝複制構造函數,然後析構掉了 m_pi 的記憶體,程式結束析構a時崩潰,解決方案是重載拷貝構造函數

class A
{
	int *m_pi;
public:
	A()
	{
		m_pi = new int;
	}
	~A()
	{
		delete m_pi;
	}
	A(A &_a)
	{
		m_pi = new int;
		*m_pi = *_a.m_pi;
	}
};

void func(A _a)
{
	int a = 0;
}      

再考慮,在A中加一個CArray對象

class A
{
	int *m_pi;
	CArray <int,int &> m_arr;
public:
	A()
	{
		m_pi = new int;
	}
	~A()
	{
		delete m_pi;
	}
	
};

void func(A _a)
{
	int t = 0;
}      

主函數:

    A a;

    func(a);

編譯報錯:

“CObject::CObject”: 無法通路 private 成員(在“CObject”類中聲明)

原因:func傳入實參後會生成臨時對象,用預設的拷貝構造函數初始化臨時對象(因為這裡未定義拷貝構造函數),而預設的拷貝構造函數會依次調用A類成員的拷貝構造函數,如果未定義,則會調用預設的,對于CArray來說,雖然未定義了拷貝構造函數,但其基類CObject定義了,但為private權限,編譯報錯。

private:

    CObject(const CObject& objectSrc);              // no implementation

    void operator=(const CObject& objectSrc);       // no implementation

對于指派操作符,同樣的

主函數

    A a;

    A b;

    b = a;       // 不同于 A b = a  出現第一種錯誤,編譯器?

報錯:

“CObject::operator =”: 無法通路 private 成員(在“CObject”類中聲明)

解決方案:

重載操作符

    A &operator=(A &)

    {

        return *this;

    }

定義拷貝構造函數

    A(A &)

再考慮

class A
{
	int m_a;
	CArray <int,int> m_arr;
public:
	A(int i){};
};

void main()
{

	A a;
	CArray<A,A &> arr;
	arr.Add(a);
}      

“A”沒有合适的預設構造函數可用

原因:

可能是因為進入CArray的類型必需有不帶參數構造函數,我們将帶參數構造函數去掉

http://hi.baidu.com/idealsoft/item/4de85dcac49b2c2847d5c07d

arr.Add(a) 時,會調用A的=,而未定義,則逐次調用成員的,包括CArray成員m_arr,因為Add函數的簽名要求輸入參數的類型為A&,是以當編譯器編譯語句:arr.Add(a); 時會自動将a強制轉換成A的引用,即将這條語句編譯成:A& newElement = b; arr.Add(newElement); 指派操作就這樣出現了!解決方案:定義=操作符

    A &operator=(A&)

http://blog.csdn.net/vincent_lon/article/details/2950218

此外,若将CArray參數改為傳值CArray<A,A> arr;,則報錯:

add 的參數變為值傳遞,需要拷貝構造函數支援,而我們的類沒有,CArray同樣沒有,CObject有,但是私有,是以編譯報錯,解決方案為定義拷貝構造函數:

    A(A &){}

    A(){}

别忘了再定義一個無參數構造函數

結論:當你的類有CArray成員時,

1 值類型,為類準備無參數構造函數,拷貝構造函數和=重載函數。

2 引用類型,=操作符,無參數構造函數

ps : 2014.6.18

CArray 繼承自 CObject, 而CArray隻顯式定義了無參數預設構造函數,而沒有定義拷貝構造和指派操作符重載函數,A在未定義相關函數的情況下進行拷貝或指派操作時,

依次調用類體各成員對象的拷貝和指派操作符重載函數,對于CArray對象,由于未顯式定義拷貝和指派操作符重載函數,故編譯器在自動生成的 copy及”=“函數中,調用基類CObject 的拷貝構造 和 ”=“操作符函數,而這兩個函數正被CObject聲明為private權限,即使在派生類CArray中亦無法通路。

得出:

在設計一個基類時,

1.禁止該類被直接執行個體化,則将構造函數申明為 private or protected,當申明為private時,該類及其所有派生類都無法執行個體化,如:

class A
{
private:
	A(){}
};

class B : public A
{
public:
	B(){}
};      

error C2248: “A::A”: 無法通路 private 成員(在“A”類中聲明)

2.如果處于安全考慮,強制要求其派生類在顯式定義 複制控制(拷貝構造和指派操作符函數),則可将 2個複制控制函數申明為private,如果申明為 protected,則隻能在類及派生類體内進行對象複制操作。

繼續閱讀