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,則隻能在類及派生類體内進行對象複制操作。