對於拷貝構造函數以及賦值構造函數的定義,我就不再囉嗦了,還是給出一個簡單的例子,更直觀些吧。
class CStr
{
public:
CStr(); //默認構造函數
CStr(const char* psz); //一種廣義拷貝構造函數,不過也有人不認同我的看法
CStr(const CStr& str); //拷貝構造函數
const CStr& operator=(const CStr& str); //賦值構造函數
size_t GetSize() const; //這裏的const是什麼意思?它必須嗎?
operator const char*() const { return m_pdata; }
protected:
const CStr* _Copy(const CStr& str);
private:
char* m_pdata;
size_t m_size;
};
CStr::CStr()
{
m_pdata = NULL;
m_size = 0;
}
size_t CStr::GetSize() const
{
return m_size;
}
const CStr* CStr::_Copy(const CStr& str)
{
if(this != &str)
{
if(m_pdata)
{
delete[] m_pdata;
}
m_size = str.GetSize();
m_pdata = new char[m_size + 1]; assert(m_pdata);
strcpy(m_pdata, str);
}
return this;
}
CStr::CStr(const char* psz) : m_pdata(NULL), m_size(0)
{
assert(psz);
if(m_pdata != psz)
{
if(m_pdata)
{
delete[] m_pdata;
}
m_size = strlen(psz);
m_pdata = new char[m_size + 1]; assert(m_pdata);
strcpy(m_pdata, psz);
}
}
CStr::CStr(const CStr& str): m_pdata(NULL), m_size(0)
{
_Copy(str);
}
const CStr& CStr::operator=(const CStr& str)
{
return *(_Copy(str));
}
int main()
{
const char* psz = "test";
const char* psz1 = "me";
CStr str(psz); //拷貝構造函數,此處調用的是CStr(const char* psz)。 #1
CStr str2(str); // 拷貝構造函數,此處調用的是 CStr(const CStr& str) #2
CStr str1 = psz1; // 拷貝構造,str1此前並不存在,現在要先構造它。 #3
str = str1; // 真正的賦值構造函數 #4
return 0;
}
上面這個小型的例子,是我剛剛爲大家編寫的,這個例子主要就是爲了闡述賦值構造函數與拷貝構造函數之間的區別,其實,我的看法是,賦值構造函數不應該被稱爲一個構造函數,充其量只能算得上一個重載的操作符函數。
在C語言中,我們知道"=="是判等操作符,而"="卻是一個賦值操作符,所以只要沒有出現"="操作符,也就不會有賦值操作可言。
我之所以認爲賦值構造函數不應該被稱爲一個構造函數,是因爲在調用賦值構造函數的時候,類對象已經存在,自然談不上構造類對象,它只是對該已經存在的類對象的成員變量進行修改(所謂的賦值)操作。而拷貝構造函數是利用一個已經存在的類對象構造出一個新的類對象。
回到上面的例子,相信大多數人都應該能分清#1、#2、#4所調用的函數,而對於#3,我想着重說明的是:賦值構造的實際用意是修改一個已有的對象,而現在str1還沒有被定義,所以此處還是必須要調用拷貝構造函數先產生一個CStr對象。
最後,請大家記住:定義與賦值同時進行的話,必須要先定義,所以必須得先調用拷貝構造函數,而對於符合單純的賦值操作語法的語句(也就是隻有兩個操作數的表達式)來說,纔是真正的調用賦值構造函數。如果大家有什麼問題,可以問我,我會盡力爲大家講解。