1. 程式人生 > >通過類String看拷貝建構函式,賦值函式的作用和區別

通過類String看拷貝建構函式,賦值函式的作用和區別

/*如果不主動編寫拷貝建構函式和賦值函式,編譯器將以“位拷貝”的方式生成自動預設函式.如果類中含有指標變數,這個預設函式會帶來錯誤.以類String的兩個物件a,b為例,a.m_str內容是"hello",b.m_str的內容為"world".將a賦給b,預設賦值函式的位拷貝意味著b.m_str=a.m_str,這樣會發生如下3個錯誤:1. b.m_str的原有記憶體沒有釋放,造成記憶體洩露;2. b.m_str和a.m_str指向同一塊記憶體,a或b的任一方變動均會影響到另一方;3. 兩個物件被析構時,會造成m_str被析構兩次*//*拷貝建構函式和賦值函式容易混淆,拷貝建構函式是物件被建立時呼叫的,賦值函式只能被已經存在了的物件呼叫*//* String a("hello"); String b("world"); String c= a;//呼叫拷貝建構函式,最好寫成String c(a); c=b;//賦值函式*///測試函式void TestStucts();class String{ char* m_str;public: //建構函式 String(const char* str){ printf("普通建構函式被執行\n"); if(NULL==str){ m_str = new char[1]; m_str[0]='\0'; } else{ m_str = new char[strlen(str)+1]; strcpy(m_str,str); } } //拷貝建構函式 String(String& self){ printf("拷貝建構函式被執行\n"); m_str = new char[strlen(self.m_str)+1]; strcpy(m_str,self.m_str); } //賦值函式 String& operator=(const String& other){//引用不可能為null,不必判斷這一層,建構函式則需要判斷傳入值 printf("賦值函式被執行\n"); if (this==&other)//1.檢查自己給自己賦值 { //不做任何處理 } else { delete m_str;//2.釋放自己原有記憶體 //3.分配新記憶體,並複製字串.strlen返回有效字串長度,不包含結束符'\0'。 //而strcpy則連結束符一起復制,因此不必擔心新的被複制字串中會缺乏結束符 m_str = new char[strlen(other.m_str)+1]; strcpy(m_str,other.m_str); } //4.返回物件的引用,為了實現鏈式表示式,千萬不能寫成return other, //因為other的生命週期不確定,甚至有可能是臨時物件,賦值後會馬上消失,那麼return other返回的將是垃圾 return *this; } //解構函式 ~String(){ delete m_str;//內部資料型別,不用delete []m_str } void Show() { printf("text is:%s\n",m_str); }};示例程式://拷貝建構函式、賦值函式 String tmpstr = String("test"); tmpstr.Show(); String a("hello"); String b("world"); String c(a); c.Show(); c=b; c.Show();